单元在ASP.NET中测试登录

时间:2009-06-04 21:38:09

标签: asp.net unit-testing tdd

我对TDD很新,而且我的单元测试有问题。我似乎无法理解下一步该做什么。 :(我正在尝试对我的一个名为AccountService的服务进行单元测试,我正在测试一个名为DoLogin的方法(用户名,密码)。这是一些示例代码:

    [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的东西。感谢

3 个答案:

答案 0 :(得分:16)

你的经历非常类似于我的开始。虽然我在TDD上出售并且不会做任何不同的事情,但我当然理解你的困惑。重要的是要记住TDD是一种设计理念。话虽如此,我想我可以帮助澄清你的一些挫折感。

  1. 首先考虑一下你想要完成什么,而不是考虑个人测试水平,但是你想要做什么。如果您的任务(用户故事)涉及获取某些凭据并尝试根据这些凭据对当前用户进行身份验证,那么请从那里开始并逐步完成。 你似乎朝这个方向前进,只是陷入了下一步

  2. 在进行单项测试时,请根据expected behavior来考虑,而不仅仅是验证某些输入和输出。把自己想象成使用这个组件,只需按照您希望的方式编写一行代码。让这部分有助于推动您的服务的接口/合同。你必须问自己一个问题,“如果我打电话给这种方法,我怎么知道它有效?我期望它做什么?”这将决定你需要做出什么样的断言。

  3. 确定您的外部依赖项是什么,以及utilize abstractions instead(依赖项反转原则)。如果您在行为验证过程中关注这些依赖关系,请使用dependency injection,以便在测试中使用mock

  4. 始终,始终,始终遵循此顺序[编写测试,观察失败,代码通过,重构]。 从我的错误中学习!!! 相信我,这是不容谈判的。否则,如果没有正确使用,您可能会将您的问题归咎于TDD。

  5. 好的,所以把这一切放在你的例子和一些很好提供的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是一个完整的设计理念。但是,它会产生更清晰的代码,更好的设计和更少的错误。

答案 1 :(得分: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

答案 2 :(得分:0)

您应该测试无效的用户名或无效的密码会导致DoLogin()失败。

给定函数的名称,(DoLogin()而不是CheckLogin())我认为该函数也应该有一些副作用。测试应验证副作用。在有人澄清应如何验证之前,真的需要澄清这是什么。