最近在看.net單元測(cè)試藝術(shù),我也喜歡單元測(cè)試,今天介紹一下如何測(cè)試異常、如何測(cè)試返回值、如何測(cè)試模擬對(duì)象的參數(shù)傳遞、如何測(cè)試數(shù)據(jù)庫(kù)訪問(wèn)代碼。單元測(cè)試框架使用的是NUnit,模擬框架使用的是:Rhino.Mocks。
1.測(cè)試異常,可以直接對(duì)方法進(jìn)行異常測(cè)試,也可以對(duì)模擬對(duì)象進(jìn)行異常測(cè)試,但是,對(duì)模擬對(duì)象進(jìn)行異常測(cè)試,很少用,所以,這里就介紹對(duì)方法的異常測(cè)試。請(qǐng)看如下代碼,當(dāng)用戶名為空的時(shí)候,拋出異常。
public bool Valid(string userName, string passWord) { if (string.IsNullOrEmpty(userName)) throw new ArgumentNullException("userName is null"); var isValid = userName == "admin" && passWord == "123456"; Log.Write(userName); return isValid; }
測(cè)試代碼如下:
[Test] [ExpectedException(typeof(ArgumentNullException))] public void Vaild_Throw_Test() { MyLogin l = new MyLogin(); l.Valid("", "123456"); }這里需要特性“ExpectedException”,意思是期待拋出一個(gè)異常。這里不需要再進(jìn)行斷言了,拋出異常后,后面的代碼也就不會(huì)執(zhí)行了。
2.測(cè)試返回值,這里主要講測(cè)試模擬對(duì)象的返回值。這里用到了一個(gè)LastCall的一個(gè)類,比較常用,一些輔助測(cè)試的功能,都在該類中。測(cè)試代碼如下:
[Test] public void Valid_Return() { MockRepository mock = new MockRepository(); var log = mock.DynamicMock<ILog>(); using (mock.Record()) { log.WriteLog("admin"); LastCall.Return(0); } var returnValue = log.WriteLog("admin"); Assert.AreEqual(returnValue, 0); } 3.測(cè)試模擬對(duì)象的參數(shù)傳遞,當(dāng)調(diào)用模擬對(duì)象時(shí),可能需要傳遞參數(shù),如果參數(shù)的值不一至?xí)r,會(huì)導(dǎo)致測(cè)試失敗,比如:我需要傳遞一個(gè)字符串,其中包含了一個(gè)GUID+UserName,這里GUID可能我們無(wú)法模擬,所以,測(cè)試參數(shù)時(shí),只需要測(cè)試UserName就可以。
方法代碼如下:
public bool Valid_Paramter(string userName, string passWord) { Log.Write(Guid.NewGuid() + userName); return userName == "admin" && passWord == "123456"; }測(cè)試代碼如下:
[Test] public void Valid_Paramter() { MockRepository mock = new MockRepository(); var log = mock.DynamicMock<ILog>(); using (mock.Record()) { log.Write("admin"); LastCall.Constraints(Rhino.Mocks.Constraints.Text.Contains("admin")); } //這里代碼如果不明白,可以看上一節(jié),里面有說(shuō)明。 MyLogin login = new MyLogin(); login.Log = log; var valid = login.Valid_Paramter("admin", "123456"); Assert.AreEqual(valid, true); mock.VerifyAll(); }這里只是測(cè)試模擬對(duì)象的參數(shù)傳遞。
4.測(cè)試數(shù)據(jù)庫(kù)訪問(wèn)代碼,這里提供的方法是,執(zhí)行完測(cè)試代碼后,對(duì)數(shù)據(jù)庫(kù)進(jìn)行回滾。有兩種實(shí)現(xiàn)方式,一種是使用Rollback特性,一種是使用TransactionScope類。其實(shí),Rollback也使用TransactionScope類。
1) Rollback特性
開始我以為Rollback是NUnit框架自帶的一個(gè)特性,結(jié)果不是,需要自己編寫代碼,這里需要繼承ITestAction接口,該接口包含BeforeTest方法和AfterTest方法。Rollback特性的代碼如下:
public class RollbackAttribute : Attribute, ITestAction { PRivate TransactionScope transaction; public void BeforeTest(TestDetails testDetails) { transaction = new TransactionScope(); } public void AfterTest(TestDetails testDetails) { transaction.Dispose(); } public ActionTargets Targets { get { return ActionTargets.Test; } } }下面是被測(cè)試的代碼,這里我用了EF框架,代碼非常簡(jiǎn)單,向TitleInfo表中,寫入數(shù)據(jù),該表中只有一個(gè)字段,就是title字段。如果寫入成功,則返回值大于0.
public int Insert(string title) { testEntities db = new testEntities(); var titleInfo = new TitleInfo() { Title = title }; db.TitleInfo.Add(titleInfo); return db.SaveChanges(); }使用Rollback特性進(jìn)行測(cè)試。
[Test] [Rollback] public void Test_Insert() { DBLibrary db = new DBLibrary(); var count = db.Insert("admin"); Assert.True(count > 0); } 非常簡(jiǎn)單,加入Rollback特性即可,這里不會(huì)向數(shù)據(jù)庫(kù)寫入記錄,但是測(cè)試會(huì)成功。
2) 使用TransactionScope類測(cè)試數(shù)據(jù)訪問(wèn)層,該類可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的事務(wù)操作,執(zhí)行測(cè)試代碼后,會(huì)對(duì)數(shù)據(jù)庫(kù)的事務(wù)進(jìn)行回滾,達(dá)到測(cè)試的目的,而不需要修改數(shù)據(jù)庫(kù)的數(shù)據(jù)。測(cè)試代碼如下:
[TestFixture] class DBLibraryTest { TransactionScope socp; [SetUp] public void Init() { socp = new TransactionScope(); } [TearDown] public void Close() { socp.Dispose(); } [Test] public void Test_Insert() { DBLibrary db = new DBLibrary(); var count = db.Insert("admin"); Assert.True(count > 0); } }這里加入了TransactionScope類,在Test_Insert方法執(zhí)行前,會(huì)先執(zhí)行Init方法,執(zhí)行完Test_Insert方法后,執(zhí)行Close方法,對(duì)事務(wù)進(jìn)行回滾。其實(shí)Rollback只是對(duì)TransactionScope進(jìn)行了封裝,通過(guò)NUnit框架,很方便的實(shí)現(xiàn)了數(shù)據(jù)庫(kù)事務(wù)的回滾。
總結(jié):這里只是總結(jié)了常用的測(cè)試方法,如果大家還有其它的常見方法,可以分享一下,大家共同學(xué)習(xí)。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注