即使断言不正确,模拟和单元测试也会通过

时间:2014-04-03 09:33:26

标签: c# unit-testing mocking xunit.net justmock

我对单元测试和整体TDD都很陌生。

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

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;
}

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

2 个答案:

答案 0 :(得分:3)

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

有关模拟的简要说明,请参阅this answer

如果您要测试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()AuthenticationServiceuserDao甚至Log,您可能需要模拟{{1}}所具有的所有依赖项。日志。)

答案 1 :(得分:3)

您已经模拟了要测试的课程。当您在Login上致电userServiceMock时,以下代码行是相关的:

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

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

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

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

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