[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的东西.谢谢
解决方法
>首先考虑一下你想要完成什么,而不是考虑个人测试水平,但是你想要做什么.如果您的任务(用户故事)涉及获取某些凭据并尝试根据这些凭据对当前用户进行身份验证,那么请从那里开始并逐步完成.你似乎正朝着这个方向前进,只会陷入下一步
>在进行单独测试时,可以用expected behavior来考虑它,而不仅仅是验证一些输入和输出.把自己想象成使用这个组件,只需按照您希望的方式编写一行代码.让这部分有助于推动您的服务的接口/合同.你必须问自己一个问题,“如果我打电话给这种方法,我怎么知道它有效?我期望它做什么?”这将决定您需要做出什么样的断言.
>确定外部依赖项是什么,以及utilize abstractions instead(依赖项反转原则).如果这些依赖关系是您关心行为验证的一部分,那么请使用dependency injection,以便在测试中使用mock.
>始终,始终,始终遵循此顺序[编写测试,观察失败,代码通过,重构].从我的错误中学习!!!相信我,这是不容谈判的.否则,如果没有正确使用,您可能会将您的问题归咎于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); }
好的,那里有很多事情要做,也许很多需要研究.但是,您可以开始了解如何使用更好的设计进行全面测试.在上面的示例中,重要的是要注意Mock对象是自定义滚动的,但您不必经历所有这些痛苦.那里有许多模拟框架.例如,使用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是一个完整的设计理念.但是,它会产生更清晰的代码,更好的设计和更少的错误.