軟件測試中基于模型生成自動化測試用例
在前面一文使用NModel自動生成測試用例中,介紹了如何通過給待測試的程序建模,生成測試用例的方法。但前面文章的問題是,生成的都是手工的測試用例,如果讓測試人員手工執行程序自動生成的測試用例,呃……這對于測試工程師來說,不蒂于一場噩夢。
自動產生的測試用例本就應該由程序自動執行,這其實也就是NModel推薦的模式。先回過頭來看看前一篇文章中制作的模型,模型里面將登錄、注銷、用戶名以及密碼等要素都抽象出來了,而NModel是以這些抽象出來的動作(登錄、注銷)和狀態(用戶名、密碼)為依據,產生測試用例的。那么要讓NModel自動執行產生的測試用例,那么它需要知道如何才能執行登錄和注銷這些動作,而且它還需要知道在執行登錄操作時,User.Administrator這個抽象出來的用戶在實際執行測試用例時,應該采用什么用戶名等信息。而這些信息NModel自己是無法“猜測”出來的,需要測試人員的引導才能獲得。
因此NModel提供了IStepper這個接口讓測試人員提供所需的信息,下面是這個接口的完整定義:
MILY: 'Courier New'">namespace NModel.Conformance { // Summary: // Must be implemented by an IUT for conformance testing public interface IStepper { // Summary: // Make a step aclearcase/" target="_blank" >ccording to the given action, the current state becomes the // target state of this transition. If the action is not enabled an exception // is thrown and the resulting state is undefined. An action on null may be // returned. // // Parameters: // action: CompoundTerm DoAction(CompoundTerm action); // // Summary: // Return to the initial state. If Reset is not enabled in the current state, // an exception is thrown and the resulting state is undefined and is thus not // guaranteed to be the initial state void Reset(); } } |
這個接口的定義非常簡單(但是實現起來就是另外一回事了),核心的函數是 DoAction,從名字可以看出,這個函數就是讓測試人員自己實現前面模型中每一個動作。而NModel的工作就是將這些動作按照模型定義好的序列組合多個基本的動作。這樣多個基本動作的組合就模擬了現實生活中,用戶使用產品時的用戶場景。在我們這個例子中,要實現的動作就是所有加上[Action]屬性的函數,即Login_Start,Logout和WebSiteModel類里面的Initialize。
我們看Initialize和Login_Start動作的實現:
private void Initialize() { TestSettings = TestLibrary.SetupTest(); } public CompoundTerm DoAction(CompoundTerm action) { switch (action.Name) { case "Initialize": Initialize(); break; case "Login_Start": string userName; modelUserToRealUser.TryGetValue((string) ((CompoundTerm)action.Arguments[0])[0], out userName); string userPass = string.Empty; switch ((string)((CompoundTerm)action.Arguments[1])[0]) { case "Correct": userPass = realUserPassword[userName]; break; case "Incorrect": userPass = wrongPassword; break; } TestSettings.UserHelper.LogOn(userName, userPass); var status = LoginStatus.Success; if (TestSettings.UserHelper.IsLoginFaled()) status = LoginStatus.Failure; break; } return null; } |
這里,我用的是Selenium來實現網站測試用例的自動化, Initialize這個動作很簡單,就是在執行所有自動化測試用例之前,做一些初始化操作,在我這個例子當中,就是啟動瀏覽器,將測試用例連接到Selenium-RC上。讀者如果不了解Selenium以及網站自動化測試的話,可以參考我的這篇文章網站測試自動化系統—基于Selenium和VSTT ,實際上Initialize函數里面的TestLibrary.SetupTest也是從那篇文章里拷貝出來的。
而Login_Start這個函數就有點復雜了,因為在模型里面,Login_Start這個動作要求兩個參數,或者說是狀態—用戶名和密碼。而且用戶分為Administrator和Authenticated兩類,密碼也類似。那么在哪個地方將這些抽象的狀態具體化呢?當然是在執行測試用例之前,要么是構造函數,要么是前文說到的 Initialize函數。我的例子里面是在構造函數里執行初始化操作:
public string wrongPassword; public Dictionary<ModelUser, RealUser> modelUserToRealUser; public Dictionary<RealUser, string> realUserPassword; public Site() { modelUserToRealUser = new Dictionary<string, string>(); modelUserToRealUser.Add("Anonymous", TestLibrary.Consts.ContributorUser); modelUserToRealUser.Add("Authenticated", TestLibrary.Consts.ModeratorUser); modelUserToRealUser.Add("Author", TestLibrary.Consts.AuthorUser); modelUserToRealUser.Add("Administrator", TestLibrary.Consts.AdminUserName); realUserPassword = new Dictionary<string, string>(); realUserPassword.Add(TestLibrary.Consts.AdminUserName, TestLibrary.Consts.CommonPassword); realUserPassword.Add(TestLibrary.Consts.AuthorUser, TestLibrary.Consts.CommonPassword); realUserPassword.Add(TestLibrary.Consts.ContributorUser, TestLibrary.Consts.CommonPassword); realUserPassword.Add(TestLibrary.Consts.ModeratorUser, TestLibrary.Consts.CommonPassword); wrongPassword = "abcefghi"; } |
將所有抽象出來的動作和狀態具體化以后,就可以讓 NModel產生測試用例并根據我們提供的信息自動執行測試用例了,下面這個命令完成這個操作:
Ct.exe /r:TrainStep.dll /r:TrainMode.dll /iut:Train.Test.Site.Create TrainMode.WebSiteModel.CreateLoginModel
Ct.exe用來產生并執行測試用例,為了完成這個工作,ct.exe需要知道模型(TrainModel.dll中的TrainModel.WebSiteModel.CreateLoginModel)和模型的一個實例(TrainStep.dll),但是/iut這個參數是干什么用的?因為一個dll文件當中,你可以有模型的多個實例,或者不同模型的實例,因此,ct.exe需要你明確指定創建模型實例的方法(Train.Test.Site.Create)。