最小起订量和多种方法设置

Moq and multiple method setup

我正在尝试同时使用 xUnit 学习最小起订量和单元测试。

我有一个身份验证逻辑 class,其中包含一些方法。它们都使用 AuthenticationDataAccessor。我正在尝试模拟该访问器以仅保留与逻辑的单元测试隔离。

我正在尝试在我的逻辑中对两种方法的逻辑进行单元测试 class。

RegisterAsync 和 AuthenticateAsync

private void SetupMocks()
        {
            // Mock the data accessor.
            var _mockedDataAccessor = new Mock<IAuthenticationData>();

            // Moke the call that will go to the mocked data accessor.
            var _mockedAuthenticationRequest = new AuthenticationRequest { Username = It.IsAny<string>(), Password = It.IsAny<string>() };
            var _mockedRegistrationRequest = new RegistrationRequest { Email = It.IsAny<string>(), Password = It.IsAny<string>(), Firstname = It.IsAny<string>(), Surname = It.IsAny<string>()  };

            // Setup the accessor.
            _mockedDataAccessor
                .Setup(x => x
                .AuthenticateAsync(_mockedAuthenticationRequest))
                .ReturnsAsync(
                    new SharedLib.Responses.UserResponse
                    {
                        ResponseState = new SharedLib.Responses.ResponseState
                        {
                            Description = "Moq description",
                            IsSuccess = true,
                            ResponseCode = ResponseCode.OK,
                            SystemError = false
                        }
                    });


            _mockedDataAccessor
                .Setup(x => x
                .RegisterAsync(_mockedRegistrationRequest))
                .ReturnsAsync(
                    new SharedLib.Responses.RegistrationResponse
                    {
                        ResponseState = new SharedLib.Responses.ResponseState
                        {
                            Description = "Moq description",
                            IsSuccess = true,
                            ResponseCode = ResponseCode.OK,
                            SystemError = false
                        }
                    });


            // Create the logic reference based on the mocked data accessor
            _logic = new AuthenticationLogic(_mockedDataAccessor.Object);

        }

所以,我有两个设置电话。一种用于我正在模拟的数据访问器方法。

但是,当我执行单元测试时:

[Fact]
public async void RegisterWithValidDetailsReturnsSuccess()
{
    SetupMocks();

    var result = await _logic.RegisterAsync(new RegistrationRequest
    {
        Email = "a.valid@email.com",
        Firstname = "ValidFirstname",
        Password = "AString@Password123",
        Surname = "AValid Surname",
        TimezoneId = 1
    });

    Assert.Equal(ResponseCode.OK, result.ResponseState.ResponseCode);
}

result 始终为空。我希望它是我在上面的设置中设置的。

请注意,使用我的 Authenticate 模拟的测试有效。看来第二次模拟失败了。

[Fact]
        public async void BlankUsernameReturnsError()
        {
            SetupMocks();

            var result = await _logic.AuthenticateAsync(new AuthenticationRequest
            {
                Password = "AFantastic123Password@",
                Username = "",
            });

            Assert.Equal(ResponseCode.LoginInvalidCredentials, result.ResponseState.ResponseCode);
        }

行得通。 也许你不能在同一个模拟 class 上有两个 'setup'?我需要为每个测试进行特定设置吗?也许 private void Setup() 是一个 problem/bad 想法?

你遇到的基本问题是:

_mockedDataAccessor
    .Setup(x => x.AuthenticateAsync(_mockedAuthenticationRequest))
    .ReturnsAsync(...));

...告诉 Moq 在 AuthenticateAsync() 传递给确切参数 时以某种方式表现。由于这不是您的测试通过的内容,因此请从包罗万象的场景开始:

_mockedDataAccessor
    .Setup(x => x.AuthenticateAsync(It.IsAny<AuthenticationRequest>()))
    .ReturnsAsync(...));

然后,如果需要,您可以缩小要求,具体取决于您的测试要达到的目标;例如当用户名是 "Alice" 时,你可以 return 一个值,当它是 "Bob":

时,你可以 return 一个值
_mockedDataAccessor
    .Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Alice")))
    .ReturnsAsync(...one value...));
_mockedDataAccessor
    .Setup(x => x.AuthenticateAsync(It.Is<AuthenticationRequest>(a => a.Username == "Bob")))
    .ReturnsAsync(...something else...));