Mock not behaving as expected when setup

Viewed 267

I am trying to test a method with the name GetAll in a xUnit-Project of the class AuhtorRepository.

public class AuthorRepository : IAuthorRepository
{
    private readonly ISqlDb _db;
    public string Connection { get; set; }
    public AuthorRepository(ISqlDb db)
    {
        _db = db;
    }

    public async Task<List<AuthorModel>> GetAll()
    {
        string sql = "SELECT * FROM Author";
        List<AuthorModel> authors = await _db.LoadDataAsync<AuthorModel, dynamic>(sql, new { }, Connection);
        return authors; 
    }

}

In this method is the LoadDataAsync method used which I will mock in my test.

The structure of the interface looks like this.

public interface ISqlDb
{
    Task<List<T>> LoadDataAsync<T, U>(string sql, U parameters, string connection);
}

Finally the implementation of the test my xUnit-Project.

using Autofac.Extras.Moq;
using DataAccess.Library;
using Moq;
using Repository.Library.Models;
using Repository.Library.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;

namespace RespositoryTests
{
    public partial class AuhtorRepositoryTests
    {
        [Fact]
        public async Task GetAll_ShouldWorkd()
        {
            using (var autoMock = AutoMock.GetLoose())
            {
                //Arrange
                autoMock.Mock<ISqlDb>()
                    .Setup(x => x.LoadDataAsync<AuthorModel, dynamic>("SELECT * FROM Author", new { }, " "))
                    .ReturnsAsync(GetSamples());

                //Act
                var cls = autoMock.Create<AuthorRepository>();
                cls.Connection = " ";
                var expected = GetSamples();

                var acutal = await cls.GetAll();

                //Assert                
                Assert.Equal(expected.Count, acutal.Count);

            }

        }

        private List<AuthorModel> GetSamples()
        {
            var authors = new List<AuthorModel>();
            authors.Add(new AuthorModel { Id = 1, FirstName = "first name", LastName = "lastname" });
            authors.Add(new AuthorModel { Id = 3, FirstName = "Angela", LastName = "Merkel" });
            return authors;
        }
    }
}

The sturcture of the project looks like this: [1]: https://i.stack.imgur.com/F4TPT.png

The test fails with the following statement:

Message: System.NullReferenceException : Object reference not set to an instance of an object.

So I expected the test should pass.

What I tried out so far:

-> I wrote a similar project with the same code, the only difference there is the project structure. Every interface and class was in the same Test-Project and the test passed.

Whereas in my BookApp Solution the ISqlDb is suited in the DataAccess.Library Project.

So it looks like that in the mocking the ReturnAsync method is not returning the values from my GetSamples.

Please bear in mind that

  • a) This is my first post on stackoverflow and
  • b) I try to make my first steps in mocking ...

tried out:

 //Act
//var cls = autoMock.Create<AuthorRepository>();
//cls.Connection = "";
var cls = new AuthorRepository(autoMock.Create<ISqlDb>());
cls.Connection = "";
var expected = GetSamples();

var acutal = await cls.GetAll();

//Assert                
Assert.Equal(expected.Count, acutal.Count);
1 Answers

The mock is returning null by default because the invocation of the mocked member does not match what was setup. Reference Moq Quickstart to get a better under standing of how to use MOQ.

You need to use argument matchers here because the anonymous new { } used in setup wont match the reference of the one actually used when exercising the test

//...

autoMock.Mock<ISqlDb>()
    .Setup(x => x.LoadDataAsync<AuthorModel, dynamic>("SELECT * FROM Author", It.IsAny<object>(), It.IsAny<string>()))
    .ReturnsAsync(GetSamples());

//...

Note the use of It.IsAny<object>() to allow whatever you pass in to be allowed.

With the above change, the test passed as expected.

Related