測試用例(Test Case)是為某個(gè)特殊目標而編制的一組測試輸入、執行條件以及預期結果,以便測試某個(gè)程序路徑或核實(shí)是否滿(mǎn)足某個(gè)特定需求。 測試用例(Test Case)目前沒(méi)有經(jīng)典的定義。比較通常的說(shuō)法是:指對一項特定的軟件產(chǎn)品進(jìn)行測試任務(wù)的描述,體現測試方案、方法、技術(shù)和策略。內容包括測試目標、測試環(huán)境、輸入數據、測試步驟、預期結果、測試腳本等,并形成文檔。
在前面的網(wǎng)站自動(dòng)化系統里面,大概聊了下如何結合Selenium生成的代碼和VSTT創(chuàng )建一個(gè)簡(jiǎn)單的自動(dòng)化系統。雖然在文章網(wǎng)站測試自動(dòng)化系統—基于Selenium和VSTT、數據驅動(dòng)測試、在測試代碼中硬編碼測試數據里,我講了一些封裝代碼以及測試數據的技巧,規避后續開(kāi)發(fā)過(guò)程中,程序員修改代碼時(shí),對測試程序帶來(lái)的影響。但是每次程序員做出大的改動(dòng)的時(shí)候,測試人員還是要修改大量的測試代碼,更糟糕的是,每次大的改動(dòng),又涉及到測試覆蓋是否足夠的問(wèn)題。為了規避類(lèi)似的風(fēng)險,以及幫助測試人員創(chuàng )建盡量多的測試用例,有些人提出了模型驅動(dòng)測試的概念。
模型驅動(dòng)測試的想法和飛機的風(fēng)洞測試差不多,即根據功能需求說(shuō)明書(shū),對要測試的程序先建立一個(gè)模型,然后有另外一個(gè)程序分析這個(gè)模型,產(chǎn)生測試用例。就好比為了驗證新飛機的氣動(dòng)布局,不可能建一個(gè)全比例的飛機,去測試它的布局是否合理;而是建立一個(gè)小的飛機模型,模型的氣動(dòng)布局和整機的布局是一致的。飛機模型建好以后,才放到風(fēng)洞里面測試一下。
市面上已經(jīng)有幾個(gè)做模型驅動(dòng)測試的工具了,這里我用的是NModel,本來(lái)想拿SpecExplorer嘗一下鮮的,但最后發(fā)現這個(gè)想法太貴了—需要安裝了Visual Studio 2010才能使用“免費”的SpecExplorer。你可以在這個(gè)網(wǎng)頁(yè)里下載 NModel:
在NModel中,測試人員使用C#創(chuàng )建程序的模型,模型創(chuàng )建的原理是:
1.程序是用來(lái)處理數據的,數據也可以稱(chēng)作狀態(tài)(State);
2.用戶(hù)通過(guò)程序提供的操作界面來(lái)處理數據,操作界面也可以稱(chēng)作動(dòng)作(Action);
3.數據的更動(dòng) 又反過(guò)來(lái)影響一些動(dòng)作是否可以執行。
比如說(shuō),使用Word的時(shí)候,剛啟動(dòng)程序時(shí)是沒(méi)有任何數據的,這個(gè)時(shí)候有些動(dòng)作,例如“保存”是禁用的。當用戶(hù)通過(guò)“新建”這個(gè)動(dòng)作創(chuàng )建了一個(gè)新文件(數據),這個(gè)新文件反過(guò)來(lái)激活“保存”動(dòng)作。
因此當測試人員建模時(shí),他要做的工作就是將程序的動(dòng)作和狀態(tài)抽象出來(lái),并且描述動(dòng)作和狀態(tài)相互影響的過(guò)程。
來(lái)看一個(gè)例子,假如現在要測試一個(gè)用戶(hù)登錄程序,登錄界面就是一個(gè)輸入用戶(hù)名和密碼的文本框,而程序支持的用戶(hù)有兩種:管理員和授權用戶(hù)。
先來(lái)做第一步,將動(dòng)作和狀態(tài)抽象出來(lái),程序的狀態(tài)應該包括:
1.程序狀態(tài):運行狀態(tài)和未運行狀態(tài)。
2.用戶(hù)類(lèi)型:管理員和授權用戶(hù)。
3.密碼:正確的密碼和錯誤的密碼。
4.登錄狀態(tài):成功登錄和登錄失敗。
動(dòng)作應該包括:
1.登錄:即用戶(hù)在界面上輸入用戶(hù)名和密碼。
2.注銷(xiāo)。
第二步,編寫(xiě)C#?程序建模。
狀態(tài)已經(jīng)抽象出來(lái)了,在NModel里面,抽象出來(lái)的狀態(tài)一般是用枚舉值表示的。
MILY: 'Courier New'">public enum ModeState { Initializing, Running }
public enum User { Authenticated, Administrator }
public enum Password { Correct, Incorrect }
public enum LoginStatus { Success, Failure } |
接下來(lái)模擬動(dòng)作:
[Feature("Login")] public static class Login { public static Map<User, LoginStatus> ActiveLoginRequests = Map<User, LoginStatus>.EmptyMap;
[Requirement("Send username and password to the server to log in.")] [Action] public static void Login_Start(User user, Password password) { if (password == Password.Correct) ActiveLoginRequests = ActiveLoginRequests.Add(user, LoginStatus.Success); else ActiveLoginRequests = ActiveLoginRequests.Add(user, LoginStatus.Failure); }
public static bool Login_StartEnabled() { return WebSiteModel.State == ModeState.Running; }
public static bool Login_StartEnabled(User user) { return !ActiveLoginRequests.ContainsKey(user) && !WebSiteModel.UsersLoggedIn.Contains(user); }
[Requirement("It should be possible to log out from any page")] [Action] public static void Logout(User user) { WebSiteModel.UsersLoggedIn = WebSiteModel.UsersLoggedIn.Remove(user); } public static bool LogoutEnabled() { return WebSiteModel.State == ModeState.Running; }
public static bool LogoutEnabled(User user) { return WebSiteModel.UsersLoggedIn.Contains(user); } } |
上面的代碼稍微解釋一下,標注了[Action]的函數,就是抽象出來(lái)的程序所支持的動(dòng)作,例如Logout;而在動(dòng)作函數名后面加上Enabled的函數,是NModel用來(lái)判定指定的動(dòng)作是否可以執行,例如LogoutEnabled函數。
Feature屬性,我們現在不講,NModel用這個(gè)屬性來(lái)標識一個(gè)大的功能。
另外要注意的是,在NModel里面,集合Set、Map是不可變的,即創(chuàng )建好了以后,就不能從里面刪除和添加新元素了。每一次修改都會(huì )創(chuàng )建一個(gè)新的Set、Map實(shí)例。所以你會(huì )看到類(lèi)似下面的用法:
ActiveLoginRequests = ActiveLoginRequests.Add(user, LoginStatus.Success);
最后,你需要采用一個(gè)工廠(chǎng)模式的方式,告訴NModel分析哪一個(gè)Feature,創(chuàng )建測試用例
public class WebSiteModel { public static ModeState State = ModeState.Initializing;
public static ModelProgram CreateLoginModel() { return new LibraryModelProgram(typeof(WebSiteModel).Assembly, "TrainMode", new Set<string>("Login")); }
[Action] public static void Initialize() { State = ModeState.Running; }
public static bool InitializeEnabled() { return State == ModeState.Initializing; }
public static Set<User> UsersLoggedIn = Set<User>.EmptySet; } |
文章來(lái)源于領(lǐng)測軟件測試網(wǎng) http://kjueaiud.com/