1

I am trying to learn MOQ as well as unit testing with xUnit at the same time.

I have an Authentication logic class with a few methods. They all make use of an AuthenticationDataAccessor. I am trying to mock out that accessor to retain unit test isolation to the logic only.

I am trying to unit test the logic of two methods within my logic class.

RegisterAsync and 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);

        }

So, I have two setup calls. One for data accessor method I am mocking out.

However, when I execute my unit test:

[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 is always null. I'd expect it to bewhat ever I set in my setup above.

Note that a test that uses my Authenticate mock, works. It seems the 2nd mock fails.

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

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

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

That works. Maybe you can't have two 'setup' on the same mocked class? And I need to have a specific setup per test? Maybe the private void Setup() is a problem/bad idea?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
Craig
  • 18,074
  • 38
  • 147
  • 248

1 Answers1

3

The basic issue you have is that this:

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

...is telling Moq to behave in a certain way when AuthenticateAsync() is passed that exact parameter. As this isn't what your tests pass, start with the catch-all scenario instead:

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

You can then narrow the requirement, if needed, depending on what your test is trying to achieve; e.g. you could return one value when the Username is "Alice", and another when it's "Bob":

_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...));
Nkosi
  • 235,767
  • 35
  • 427
  • 472
sellotape
  • 8,034
  • 2
  • 26
  • 30