VS2010 測試功能之旅:編碼的UI測試(4)-通過編寫測試代碼的方式建立UI測試(上)
回顧
在之前的入門篇系列中,分別介紹了一個簡單的示例, 操作動作的錄制原理,通過修改UIMap.UItest文件控制操作動作代碼的生成,對象的識別原理。接下來正式進入我們UI測試的進階篇,在這一章,將講述如何初步通過自己編寫代碼的方式來建立UI測試。
示例程序
一個系統的基本功能是增,刪,改,查,其中增和改界面基本一樣,刪就幾乎是一個按鈕的事,所以我做了一個程序示例(下載點我),擁有增和查兩個功能,之后的操作都將會在這個示例之上進行:
系統主窗口:
該系統擁有兩個功能,“添加用戶”和“查詢用戶”,點擊添加用戶后,進入添加用戶子窗體:
這里添加用戶的時候根據情況會出現以下幾個提示框:
“用戶名不能為空”
“已有重名用戶”
“備注不能為空”
“添加成功!”
如果在之前的主窗口,點擊查詢用戶,則進入查詢用戶子窗體。
注:系統默認自帶了5個用戶TestUser1, TestUser2, TestUser3, TestUser4, TestUser5。
這個窗體不會彈任何提示框,默認進入窗體時,DataGridView里面沒有加載數據,現在進行一個說明:
查詢條件-用戶名:表示是否按用戶名查詢(非模糊查詢),如果不輸入,默認為不按其查詢。
查詢條件-用戶類型:有三個選項“所有”,“管理員”,“一般用戶”。
查詢條件-日期:表示是否按日期查詢,如果勾上了日期CheckBox,則旁邊的DateTimePicker會啟用,然后選擇一個具體的日期。
按鈕-查詢:就會按以上條件查詢。
按鈕-重置:用戶名清空,用戶類型變成所有,日期取消勾選。
文本框-用戶備注:當查詢出數據以后,每選擇DataGridView里面中的一行數據,用戶備注TextBox會自動加載當前行的用戶備注。
因為篇幅的關系,這里仍然分為上下兩部分,上部分介紹添加用戶窗體,下部分介紹查詢用戶窗體和測試之間的銜接。
如何設計測試
首先從前面的分析中,就可以得出添加用戶實際上是檢測是否有那些反例的彈出框彈出,然后正確添加用戶,這里設計了一些檢查點。
步驟序號 |
操作步驟 |
檢查點 |
1 |
運行主程序exe |
檢測系統主窗口是否彈出 |
2 |
點擊添加用戶 |
檢測添加用戶子窗口是否彈出 |
3 |
輸入用戶名為空,用戶類型選擇“一般用戶”,備注為空 |
檢測是否彈出“用戶名不能為空” |
4 |
輸入用戶名為“TestUser1”(系統默認就已有該用戶),用戶類型選擇“一般用戶”,備注為空 |
檢測是否彈出“已有重名用戶” |
5 |
輸入用戶名為“TestUser6”,用戶類型選擇“一般用戶”,備注為空 |
檢測是否彈出“備注不能為空” |
6 |
輸入用戶名為“TestUser6”,用戶類型選擇“一般用戶”,備注為“Test” |
檢測是否彈出“添加成功!” |
7 |
點擊取消按鈕,并退出主窗體 |
檢測是否退出添加用戶子窗體和主窗體 |
接下來要做的工作就很輕松,我們要將以上的檢查點轉換為代碼。
對測試進行編碼
實際上,很多自動化測試項目在編寫的時候都是采用邊錄制邊編寫的方法來進行的,比如復雜的操作可以先錄制下來,然后手工去改某些步驟,這里我們將采用這種方法。
我們需要新建一個項目,然后在添加一個編碼的UI測試映射,命名為AddUserUIMap.uitest,建立之后,錄制生成器會自動彈出,這個時候,我們什么也不做,直接點擊“生成代碼”,這樣VS2010就會自動生成AddUserUIMap.cs文件和AddUserUIMap.Designer.cs文件,在第二章(下)已經提到,自定義代碼可以編寫到.cs文件下,因為這里不會被覆蓋。
實現步驟1
為了實現第一步檢查點,首先我們需要捕獲主窗體對象,首先我們需要打開示例程序,然后點擊錄制生成器的準星。
從點擊準星的那一刻起,按住鼠標不放,將鼠標挪動到主窗體直到主窗體被藍色框選中,這個時候便可以松開鼠標。
之后我們可以看到對象庫中識別了該對象,現在點擊對象庫上面的“添加”圖標,就可以將這個對象正式加入對象庫:
然后選擇錄制生成器的生成代碼。
之后對象識別代碼就生成在了AddUserUIMap.Designer.cs。
之后我們就可以進入AddUserUIMap.cs(注,這里是.cs,不是.Designer.cs),實現我們第一個步驟的代碼Step1_LoginSystem()。
{
//操作步驟:假設程序在D盤,這句的作用是加載程序
ApplicationUnderTest.Launch(@"D:\TestDemo.exe");
//檢查點:this.UI系統主窗口Window.WaitForControlExist(6000)的作用為,最多花6秒的時間等待UI系統主窗口Window出現,如果沒有出現,返回false,如果出現了,則返回true
Assert.IsTrue(this.UI系統主窗口Window.WaitForControlExist(6000), "運行主程序exe,檢測系統主窗口彈出失敗");
}
實現步驟2
第一步就完成了,接下來實現第二步Step2_ClickAddUser(),因為這里大家可能覺得錄制生成的方式更方便,這里我們可以采用錄制的方式先生成代碼,之后再將.Designer.cs生成的代碼遷移到.cs文件下。
首先打開錄制生成器的錄制。
然后在菜單中選擇“添加用戶”。
然后停止錄制,點擊生成代碼,生成Step2_ClickAddUser()。
生成完畢,我們可以看到在.Designer.cs下生成了如下代碼。
{
#region Variable Declarations
WinMenuItem uI添加用戶MenuItem = this.UI系統主窗口Window.UIMenuStrip1MenuBar.UI用戶管理MenuItem.UI添加用戶MenuItem;
#endregion
// Click '用戶管理' -> '添加用戶' menu item
Mouse.Click(uI添加用戶MenuItem, new Point(41, 7));
}
這里我們把這些代碼從.Designer.cs剪切到.cs文件下,然后刪除AddUserUIMap.uitest文件下<ExecuteActions>節點中的所有內容,因為根據操作動作的錄制原理可以了解到,.Designer.cs會根據.uitest文件生成代碼,所以需要清空這個節點。
當然這里僅僅是操作步驟實現了,但我們還要驗證“添加用戶”窗口是否彈出,采用和第一步相同的方式,將添加用戶這個窗口添加到對象庫,然后生成識別代碼。
之后就可以將Step2_ClickAddUser()的檢查點也實現了,具體代碼如下。
{
//操作步驟:在菜單中選擇添加用戶
WinMenuItem uI添加用戶MenuItem = this.UI系統主窗口Window.UIMenuStrip1MenuBar.UI用戶管理MenuItem.UI添加用戶MenuItem;
Mouse.Click(uI添加用戶MenuItem, new Point(1, 1));
//檢查點:檢查添加用戶子窗口是否彈出
Assert.IsTrue(this.UI添加用戶Window.WaitForControlExist(6000), "點擊添加用戶,檢測添加用戶子窗口彈出失敗");
}
實現步驟3-6
接下來,就是第3步到第6步的檢測,3到6步基本上就只有以下幾個動作。
a.輸入用戶名
b.選擇用戶類別
c.填入備注
d.點擊添加按鈕
e.彈出提示框,驗證文本,點擊OK
除了e步驟的“驗證文本”操作的彈出框不是一個對象,其他的操作的對象都是一樣的(OK這個button雖然屬于不同的彈出框,但VS2010默認識別時會把它當成同一個,神奇吧),所以這部分操作代碼是可以重用的,所以我們先打開錄制生成器,然后錄制以上的操作,并生成代碼,和之前一樣,這些代碼都會從.designer.cs文件下剪切到.cs文件。(如何解決e步驟的“驗證文本”操作的彈出框不是一個對象的問題,這個一會兒會介紹)。
{
#region Variable Declarations
WinEdit uITbx_UserNameEdit = this.UI添加用戶Window.UITbx_UserNameWindow.UITbx_UserNameEdit;
WinComboBox uI用戶類別ComboBox = this.UI添加用戶Window.UICbx_UserTypeWindow.UI用戶類別ComboBox;
WinEdit uITbx_MemoEdit = this.UI添加用戶Window.UITbx_MemoWindow.UITbx_MemoEdit;
WinButton uI添加Button = this.UI添加用戶Window.UI添加Window.UI添加Button;
WinButton uIOKButton = this.UIOKWindow.UIOKButton;
#endregion
// Type 'comeon' in 'Tbx_UserName' text box
uITbx_UserNameEdit.Text = this.RecordedMethod2Params.UITbx_UserNameEditText;
// Select '一般用戶' in '用戶類別:' combo box
uI用戶類別ComboBox.SelectedItem = this.RecordedMethod2Params.UI用戶類別ComboBoxSelectedItem;
// Type 'comeon' in 'Tbx_Memo' text box
uITbx_MemoEdit.Text = this.RecordedMethod2Params.UITbx_MemoEditText;
// Click '添加' button
Mouse.Click(uI添加Button, new Point(52, 17));
// Click 'OK' button
Mouse.Click(uIOKButton, new Point(24, 7));
}
接下來就該解決e步驟的“驗證文本”操作的彈出框不是一個對象的問題了。
在第一章:一個簡單的示例中,里面的彈出框是很難重用的,例如文本為“密碼錯誤”和文本為“登陸成功”的彈出框,VS2010識別時會默認當他是兩個對象,因此在對象庫里面也是兩個對象,但實際上,為了避免對象庫對象過多,完全可以把它當成一個對象,只是說文本不一樣,根據對象的識別原理,我們可以更改他的關鍵標識屬性,讓VS2010把所有的文本不同的彈出框都當成一個對象識別,然后在測試時把它的文本屬性用來比對就OK了。
現在我們故意讓“用戶名不能為空”的彈出框彈出,然后捕獲上面的。
然后可以看到對象庫添加了這兩個對象。
然后我們將其保存,并生成代碼,之后關閉錄制生成器(一定要關閉),進入.uitest文件,尋找到對應的識別代碼。
<TechnologyName>MSAA</TechnologyName>
<WindowTitles>
<WindowTitle>用戶名不能為空</WindowTitle>
</WindowTitles>
<SearchConfigurations>
<SearchConfiguration>VisibleOnly</SearchConfiguration>
</SearchConfigurations>
<AndCondition Id="SearchCondition">
<PropertyCondition Name="Name">用戶名不能為空</PropertyCondition>
<PropertyCondition Name="ClassName">Static</PropertyCondition>
<PropertyCondition Name="ControlType">Window</PropertyCondition>
</AndCondition>
<SupportLevel>1</SupportLevel>
<Descendants>
<UIObject ControlType="Text" Id="UI用戶名不能為空Text" FriendlyName="用戶名不能為空" SpecialControlType="None">
<TechnologyName>MSAA</TechnologyName>
<WindowTitles>
<WindowTitle>用戶名不能為空</WindowTitle>
</WindowTitles>
<SearchConfigurations>
<SearchConfiguration>VisibleOnly</SearchConfiguration>
</SearchConfigurations>
<AndCondition Id="SearchCondition">
<PropertyCondition Name="Name">用戶名不能為空</PropertyCondition>
<PropertyCondition Name="ControlType">Text</PropertyCondition>
</AndCondition>
<SupportLevel>1</SupportLevel>
<Descendants />
</UIObject>
</Descendants>
</TopLevelWindow>
現在我們將其進行修改,根據對象的識別原理,更改部分關鍵標識屬性,并刪掉一些意義不大的代碼,讓其能夠識別所有不同文本的彈出框。
修改之后的代碼如下:
<TechnologyName>MSAA</TechnologyName>
<AndCondition Id="SearchCondition">
<!--這里刪去了自動生成的<PropertyCondition Name="Name">用戶名不能為空</PropertyCondition>-->
<PropertyCondition Name="ClassName">Static</PropertyCondition>
<PropertyCondition Name="ControlType">Window</PropertyCondition>
</AndCondition>
<SupportLevel>1</SupportLevel>
<Descendants>
<UIObject ControlType="Text" Id="UI彈出框Text">
<TechnologyName>MSAA</TechnologyName>
<AndCondition Id="SearchCondition">
<!--這里刪去了自動生成的<PropertyCondition Name="Name">用戶名不能為空</PropertyCondition>-->
<PropertyCondition Name="ControlType">Text</PropertyCondition>
</AndCondition>
<Descendants />
</UIObject>
</Descendants>
</TopLevelWindow>
然后我們打開錄制生成器,查看修改過后的對象,可以看到連名字都變了,同時也能夠識別出所有彈出框對象。
因為目前錄制生成器是從.uitest文件讀出來的,但是designer.cs的代碼還未生成,所以根據操作動作的錄制原理,我們還需要點擊一次“生成代碼”,然后真正起識別作用的代碼就會生成到.designer.cs文件下。
以后我們就可以通過在代碼中“this.UI彈出框Window.UI彈出框Text ”來控制彈出框了。
接下來刪掉<ExecuteActions>節點中的所有內容,并將之前錄制到的操作代碼從.Designer.cs文件剪切到.cs文件下并進行修改,一個增加4個方法Step3_AddUserWithNoName(),Step4_AddUserWithOverlapName(),Step5_AddUserWithNoMemo(),Step6_AddUserSuccess(),修改之后的代碼如下所示。
特別注意:從step4開始檢查點前面都加了一句this.mUI彈出框Window = new UI彈出框Window();之所以這么加是因為上一個操作step3已經識別了“用戶名不能為空”彈出框,個人推測VS2010這時會把這個“UI彈出框Window”對象指向到“用戶名不能為空”彈出框的句柄,然后雖然關閉了“用戶名不能為空”彈出框,但句柄的值依然指向它,這就直接導致從step4開始的時候無法用對象“UI彈出框Window”來識別出“已有重名用戶”的彈出框,所以只好將這個對象重新實例化一次。除了彈出框,其他的窗體也有這樣的特點。
{
//操作步驟
this.UI添加用戶Window.UITbx_UserNameWindow.UITbx_UserNameEdit.Text = "";
this.UI添加用戶Window.UICbx_UserTypeWindow.UI用戶類別ComboBox.SelectedItem = "一般用戶";
this.UI添加用戶Window.UITbx_MemoWindow.UITbx_MemoEdit.Text ="";
Mouse.Click(this.UI添加用戶Window.UI添加Window.UI添加Button, new Point(1, 1));
//檢查點:首先檢查3秒內是否有彈出框彈出,如果有,則檢查文本是否是"用戶名不能為空"
bool isPopUp = this.UI彈出框Window.UI彈出框Text.WaitForControlExist(3000);
Assert.IsTrue(isPopUp&&this.UI彈出框Window.UI彈出框Text.DisplayText == "用戶名不能為空", "輸入用戶名為空,檢測彈出“用戶名不能為空”失敗");
Mouse.Click(this.UIOKWindow.UIOKButton, new Point(1, 1));
}
public void Step4_AddUserWithOverlapName()
{
//操作步驟
this.UI添加用戶Window.UITbx_UserNameWindow.UITbx_UserNameEdit.Text = "TestUser1";
this.UI添加用戶Window.UICbx_UserTypeWindow.UI用戶類別ComboBox.SelectedItem = "一般用戶";
this.UI添加用戶Window.UITbx_MemoWindow.UITbx_MemoEdit.Text = "";
Mouse.Click(this.UI添加用戶Window.UI添加Window.UI添加Button, new Point(1, 1));
//檢查點:首先檢查3秒內是否有彈出框彈出,如果有,則檢查文本是否是"已有重名用戶"
this.mUI彈出框Window = new UI彈出框Window();
bool isPopUp = this.UI彈出框Window.UI彈出框Text.WaitForControlExist(3000);
Assert.IsTrue(isPopUp&&this.UI彈出框Window.UI彈出框Text.DisplayText == "已有重名用戶", "輸入重名用戶,檢測彈出“已有重名用戶”失敗");
Mouse.Click(this.UIOKWindow.UIOKButton, new Point(1, 1));
}
public void Step5_AddUserWithNoMemo()
{
//操作步驟
this.UI添加用戶Window.UITbx_UserNameWindow.UITbx_UserNameEdit.Text = "TestUser6";
this.UI添加用戶Window.UICbx_UserTypeWindow.UI用戶類別ComboBox.SelectedItem = "一般用戶";
this.UI添加用戶Window.UITbx_MemoWindow.UITbx_MemoEdit.Text = "";
Mouse.Click(this.UI添加用戶Window.UI添加Window.UI添加Button, new Point(1, 1));
//檢查點:首先檢查3秒內是否有彈出框彈出,如果有,則檢查文本是否是"備注不能為空"
this.mUI彈出框Window = new UI彈出框Window();
bool isPopUp = this.UI彈出框Window.UI彈出框Text.WaitForControlExist(3000);
Assert.IsTrue(isPopUp&&this.UI彈出框Window.UI彈出框Text.DisplayText == "備注不能為空", "輸入備注為空,檢測彈出“備注不能為空”失敗");
Mouse.Click(this.UIOKWindow.UIOKButton, new Point(1, 1));
}
public void Step6_AddUserSuccess()
{
//操作步驟
this.UI添加用戶Window.UITbx_UserNameWindow.UITbx_UserNameEdit.Text = "TestUser6";
this.UI添加用戶Window.UICbx_UserTypeWindow.UI用戶類別ComboBox.SelectedItem = "一般用戶";
this.UI添加用戶Window.UITbx_MemoWindow.UITbx_MemoEdit.Text = "Test";
Mouse.Click(this.UI添加用戶Window.UI添加Window.UI添加Button, new Point(1, 1));
//檢查點:首先檢查3秒內是否有彈出框彈出,如果有,則檢查文本是否是"添加成功!"
this.mUI彈出框Window = new UI彈出框Window();
bool isPopUp = this.UI彈出框Window.UI彈出框Text.WaitForControlExist(3000);
Assert.IsTrue(isPopUp&&this.UI彈出框Window.UI彈出框Text.DisplayText == "添加成功!", "輸入正確,檢測彈出“添加成功!”失敗");
Mouse.Click(this.UIOKWindow.UIOKButton, new Point(1, 1));
}
實現步驟7
現在就只差最后一步了,就是關閉兩個窗體,采用之前的方式,先錄制關閉操作,先讓操作代碼生成在Designer.cs,然后在把它剪切到.cs下,最后添加驗證邏輯,錄制就不詳細說明了,最終代碼如下:
{
//操作步驟
bool isClosed;
Mouse.Click(this.UI添加用戶Window.UI取消Window.UI取消Button, new Point(1, 1));
//和WaitForControlExist相反,這里是最長等待他3秒關閉,如果3秒內關閉返回true,否則為false
isClosed= this.UI添加用戶Window.WaitForControlNotExist(3000);
Mouse.Click(this.UI系統主窗口Window.UI系統主窗口TitleBar.UICloseButton, new Point(1, 1));
isClosed &= this.UI系統主窗口Window.WaitForControlNotExist(3000);
//檢查點
Assert.IsTrue(isClosed, "點擊退出,檢測是否退出添加用戶子窗體和主窗體失敗");
}
總結
在本章上部分,介紹了通過編碼的方式來建立UI測試,在這里首先實現了添加用戶窗體上的操作,相信大家在看完了以后,應該能夠對UI測試有一個更深的認識了,如果需要調用剛才所寫的方法,只需要再新建一個編碼的UI測試,例如將其命名為CodedUITest1.cs,然后在內部添加一個這樣的調用即可。
public void CodedUITestMethod1()
{
AddUserUIMapClasses.AddUserUIMap uimap = new AddUserUIMapClasses.AddUserUIMap();
uimap.Step1_LoginSystem();
uimap.Step2_ClickAddUser();
uimap.Step3_AddUserWithNoName();
uimap.Step4_AddUserWithOverlapName();
uimap.Step5_AddUserWithNoMemo();
uimap.Step6_AddUserSuccess();
uimap.Step7_CloseWindows();
}
示例程序的下載:下載點我
個人錄制的源代碼下載:下載點我
下部分將介紹查詢用戶窗體的測試代碼的編寫,以及他們測試的關聯。