0

总的来说,我对单元测试和 TDD 很陌生。

我在作为 Windows 服务托管的服务层 (WCF) 中有以下登录方法。我的服务层遵循外观模式,所有对服务层的调用都是用请求对象进行的,并返回相应的响应对象。

public LoginResponse Login(LoginRequest request)
{
    var response = new LoginResponse(request.RequestId);
    try
    {
        if (!ValidRequest(request, response, Validate.ClientTag))
            return response;

        var user = userDao.GetByUserId(request.UserId);
        if (user != null)
        {                   
            if (request.Password != "")
            {
                var authenticationService = new AuthenticationService();
                if (authenticationService.Authenticate(user, request.Password))
                {                          
                    return response;
                }                        
                response.ErrorCode = "IncorrectPassword";
            }
            else
            {                       
                response.ErrorCode = "PasswordNotFound";
            }
        }
        else
        {
            response.ErrorCode = "UserNotFound";
        }
        response.Acknowledge = AcknowledgeType.Failure;
        return response;
    }
    catch (Exception ex)
    {
        Log.Error(ex);
        response.Acknowledge = AcknowledgeType.Failure;
        response.ErrorCode = "Exception";
        return response;
    }
}

这里的两行:

userDao.GetByUserId(request.UserId);

authenticationService.Authenticate(user, request.Password);

正在调用数据库。

这是我用 xUnit 和 JustMock 编写的测试:

    [Theory]
    [InlineData("manager", "manager")]
    public void LoginTest(string userId, string password)
    {
        //Arrange
        var userServiceMock = Mock.Create<IUserManagementService>();

        var request = new LoginRequest().Prepare();
        request.UserId = userId;
        request.Password = password;

        var response = new LoginResponse(request.RequestId);

        Mock.Arrange(() => userServiceMock.Login(request)).Returns(response).OccursOnce();

        //Act
        userServiceMock.Login(request);

        //Assert
        Mock.Assert(userServiceMock);            
    }

我遇到的问题是即使在我将服务方法更改为

public LoginResponse Login(LoginRequest request)
{
    return null;
}

我的测试仍然通过。我究竟做错了什么?

4

2 回答 2

3

你没有测试任何东西。您正在嘲笑您的测试系统,这是不正确的。

有关什么是模拟的简要说明,请参阅此答案

如果你正在测试UserManagementService.Login(),你会想要:

[Theory]
[InlineData("manager", "manager")]
public void LoginTest(string userId, string password)
{
    // Arrange
    // System under test
    IUserManagementService userService = new UserManagementService();

    var request = new LoginRequest().Prepare();
    request.UserId = userId;
    request.Password = password;

    var expectedResponse = new LoginResponse(request.RequestId);

    //Act
    var actualResponse = userService.Login(request);

    //Assert
    Assert.AreEqual(actualResponse.Something, expectedResponse.Something);            
}

无需嘲笑任何东西。(您可能需要模拟任何Login()具有诸如AuthenticationService,的依赖项,userDao即使Log您不希望单元测试写入日志。)

于 2014-04-03T09:50:17.143 回答
3

您已经模拟了要测试的课程。当您调用LoginuserServiceMock,以下代码行是相关的:

Mock.Arrange(() => userServiceMock.Login(request)).Returns(response).OccursOnce();

也就是说,您总是返回一个有效的结果。实际代码永远不会执行。

您的每个单元测试都将有一个“被测系统”(SUT)。您永远不会想模拟 SUT 本身。您只模拟您的 SUT 所依赖的任何其他对象。在您的情况下,这UserService似乎是您的 SUT。没有理由嘲笑用户服务,您要测试真实的!

然而,SUT 似乎使用了UserDao可能在某处注入的 a。注入 UserDAO 的模拟而不是真实的模拟。

此外,它使用AuthenticationService. 不幸的是,它没有被注入,但您的方法会动态创建一个实例。这使得无法使用它的模拟实现。您将需要重构您的 UserService 以便您可以注入AuthenticationService要使用的。然后你的单元测试可以注入一个模拟的AuthenticationService.

于 2014-04-03T09:50:23.600 回答