2009-06-04 70 views
5

我對TDD非常陌生,並且在單元測試中遇到問題。我似乎無法理解接下來要做什麼。 。:(我試圖單元測試稱爲帳戶服務我的服務,我正在測試一個名爲DoLogin(用戶名,密碼)的方法下面是一些示例代碼:在ASP.NET中對登錄進行單元測試

[Test] 
    public void User_With_Correct_Username_And_Pass_Should_Login_Successfully() 
    { 
     // Arrange 
     var accountService = new AccountService(); 

     // Act 
     bool result = accountService.DoLogin("test", "test"); 

     // Assert 
     Assert.IsTrue(result); 
    } 

    public class AccountService : IAccountService 
    { 
     public bool DoLogin(string username, string password) 
     { 
     if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) 
      return false; 

     return true; 
     } 
    } 

因此本次測試的過去,但現在做什麼我做了什麼?!如何真正測試一個有效的登錄是否發生?我是否需要實現一個集成測試並根據真實或內存數據庫測試登錄?對不起,如果我做的事情完全不正確。天得到這個TDD的東西了。感謝

回答

14

你的經驗是非常相似的礦山開始了。雖然我在TDD上銷售,不會做任何不同的事情,但我當然明白你的困惑。重要的是要記住TDD是一種設計理念。話雖如此,我想我可以幫助清除你的一些挫折。

  1. 從考慮你想要完成的事情開始,而不是在單獨的測試級別上,但是你試圖做什麼。如果您的任務(用戶故事)涉及獲取某些憑證並嘗試根據這些憑證對當前用戶進行身份驗證,那麼請從此處開始並按順序進行。 你似乎在這個方向前進,只是卡住在接下來的步驟中

  2. 在單獨的測試工作時,在expected behavior方面,而不是僅僅檢驗一些輸入和輸出想到它。把你自己想象成使用這個組件,並且簡單地按照你想要的方式編寫一行代碼。讓這部分幫助驅動你的服務的接口/合同。你必須問自己這個問題:「如果我打電話給這個方法,我怎麼知道它的工作原理?我期望它做什麼?」這將決定你需要做什麼樣的斷言。

  3. 確定你的外部依賴是什麼,和utilize abstractions instead(依賴倒置原則)。如果這些依賴關係是您關心的行爲驗證的一部分,請使用dependency injection,以便您可以在測試中使用mock

  4. 總是,總是按照這個順序[寫下你的測試,看它失敗,代碼通過,重構]。 從我的錯誤中學習!相信我,這是不可協商的。否則,當TDD沒有被正確使用時,你有責任責怪你的問題。

好了,你的榜樣把所有這些組合起來,有些很好的提供test cases from lance,我們可以做這樣的事情:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsTrue(service.DoLogin("Name", "Password")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

[Test] 
public void ShouldNotAuthenticateUserWithInvalidPassword() 
{ 
    IMyMockDa mockDa = new MockDataAccess(); 
    var service = new AuthenticationService(mockDa); 

    mockDa.AddUser("Name", "Password"); 

    Assert.IsFalse(service.DoLogin("Name", "BadPassword")); 

    //Ensure data access layer was used 
    Assert.IsTrue(mockDa.GetUserFromDBWasCalled); 
} 

好了,所以有很多事情在那裏,也許很多研究。但是,您可以開始瞭解如何通過使用更好的設計來進行徹底測試。在上面的例子中,重要的是要注意,模擬對象是自定義滾動的,但你不必經歷所有這些痛苦。那裏有很多模擬框架。例如使用RhinoMocks,您的測試應該是這樣的:

[Test] 
public void ShouldAuthenticateValidUser() 
{ 
    var mockRepo = new MockRepository(); 
    var mockDa = mockRepo.DynamicMock<IMyMockDa>(); 

    var service = new AuthenticationService(mockDa); 

    using(mockRepo.Record()) 
    { 
     //I realize this is a terrible method and should not exist if you 
     // care about security, but for demonstration purposes... 
     Expect.Call(mockDa.GetPassword("User")).Return("Password"); 
    } 
    using(mockRepo.Playback()) 
    { 
     Assert.IsTrue(service.DoLogin("User", "Password")); 
    } 
} 

習慣於先做事手工的方式,所以你理解的概念,然後移動到使用的框架。呼!很多信息,但正如你所看到的,TDD是一個完整的設計理念。但是,它會產生更清晰的代碼,更好的設計和更少的錯誤。

0

你應該有一個測試,一個無效的用戶名或密碼無效導致DoLogin()失敗。

賦予的名稱(DoLogin()而不是CheckLogin()),我認爲這個函數也應該有一些副作用。測試應該驗證那邊影響。真的需要澄清是什麼之前,有人可以澄清應該如何驗證。

1

將您所知道的有效和無效憑據傳遞給DoLogin,然後將結果與預期結果進行比較。嘗試想象用戶將提供的「用戶名」和「密碼」參數的每種可能的(閱讀:合理的)組合/輸入,併爲每種參數創建測試。

如果您的DoLogin業務邏輯是可信的,我們將定義一個「有效」用戶名(以及「有效」密碼)爲任何填充的內容。爲了討論的緣故,公平了。

一些簡單的測試浮現在腦海中:

Login_With_Null_UserName_Fails() 
Login_With_Populated_UserName_Succeeds() 
Login_With_Empty_UserName_Fails() 
Login_With_Null_Password_Fails() 
Login_With_Populated_Password_Succeeds() 
Login_With_Empty_Password_Fails() 

或者,考慮組合:

Login_With_Null_UserName_And_Populated_Password_Fails() 
Login_With_Populated_UserName_And_Populated_Password_Succeeds() 
Login_With_Empty_UserName_And_Null_Password_Fails() 
etc 
etc 
+0

很酷,謝謝。所以在完成DoLogin的測試列表後,我的下一步是什麼?然後,我真的測試登錄對數據庫? – CalebHC 2009-06-04 23:28:31

+0

如果您認爲在將參數發送到存儲過程並從存儲過程獲得正確結果方面存在足夠的風險,那麼當然! 測試有助於降低風險並改善代碼。我推薦您在任何地方合理預測任何機會的測試。 – lance 2009-06-05 14:23:58