Search code examples
c#unit-testingxamarin.formsmockingautofac

Autofac.Extras.Moq - response from mocked Login does not contain expected value


I want to make unit tests in my app. I use NUNIT, and the following libraries :

  • Autofac.Extras.Moq
  • AutoFixture

I followed this samples but it doesn't work :

Here is my test :

private Fixture _fixture;

[SetUp]
public void Setup()
{
   _fixture = new Fixture();
}

[Test]
public void Login_Success()
{
   using (var mock = AutoMock.GetLoose())
   {
      var infosLogin = _fixture.Create<LoginRequest>();
      var loginResponse = _fixture.Create<LoginResponse>();

      var userService = mock.Mock<IUserService>();
      userService
         .Setup(user => user.Login(infosLogin))
         .Returns(Task.FromResult(loginResponse));

      var viewModel = new MainPageViewModel(new ContentPage(), userService.Object);

      viewModel.Login = infosLogin.Username;
      viewModel.Password = infosLogin.Password;
      viewModel.LoginCommand.Execute(null);
   }
}

My view

public MainPage()
{
   InitializeComponent();
   BindingContext = new MainPageViewModel(this, new UserServiceImpl());
}

My ViewModel

public MainPageViewModel(Page page, IUserService userService)
{
   _page = page;
   _userService = userService;

   Login = "";
   Password = "";
}

public Command LoginCommand
{
   get
   {
      return new Command(async () =>
      {
         Console.WriteLine("step 1...");

         if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password))
         {
            Console.WriteLine("step 2...");
            var infos = new LoginRequest() { Username = "Wyllis", Password = "test" };
            LoginResponse response = await _userService.Login(infos);
            Console.WriteLine("step 3...");
            Console.WriteLine(response);
            Age = response.Age; // Got error : Object reference not set to an instance of an object
         }
      });
   }
}

LoginResponse model

public class LoginResponse
{
   public string Username { get; set; }
   public string Age { get; set; }
}

Age = response.Age;, I Got error : Object reference not set to an instance of an object, can you explain what is wrong ?


Solution

  • I found the solution, new LoginRequest(...) from my viewmodel and my tests are same BUT the hashcode (memory address) is different, so my test fail because my param is not the same object with the same memory than viewmodel

    here is my new test and my view model

    ViewModel

    public Command LoginCommand
    {
       get
       {
          return new Command(async () =>
          {
             if (!string.IsNullOrEmpty(Login) && !string.IsNullOrEmpty(Password))
             {
                var infos = new LoginRequest() { Username = Login, Password = Password };
                LoginResponse response = await _userService.Login(infos);
    
                Age = response.Age;
             }
          });
       }
    }
    

    Test

    private Mock<IUserService> _userService;
    private MainPageViewModel _viewModel;
    private Fixture _fixture;
    
    [SetUp]
    public void Setup()
    {
                using (var mock = AutoMock.GetLoose())
                {
                    _userService = mock.Mock<IUserService>();
                }
                _fixture = new Fixture();
            }
    
            private MainPageViewModel CreateInstance()
            {
                return new MainPageViewModel(_userService.Object);
            }
    
            [Test]
            public void Test_Constructor()
            {
                using (var mock = AutoMock.GetLoose())
                {
                    var viewModel = mock.Create<MainPageViewModel>();
    
                    viewModel.Login.Equals("");
                    viewModel.Password.Equals("");
                }
            }
    
            [Test]
            public void Login_Success()
            {
                var user = _fixture.Create<LoginResponse>();
    
                _viewModel = CreateInstance();
                _viewModel.Login = "test";
                _viewModel.Password = "test";
    
                _userService
                    .Setup(s => s.Login(It.IsAny<LoginRequest>()))
                    .Returns(Task.FromResult(user))
                    .Verifiable();
    
                _viewModel.LoginCommand.Execute(null);
    
                _userService.Verify();
    
                Assert.AreEqual(_viewModel.Age, user.Age);
            }