2

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);
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • If you are writing test for AuthorRepository class then you need to create an object of that class. `var cls = autoMock.Create();` is not needed... you need to do `var cls = new AuthorRepository(autoMock.Create();` – Chetan Jul 10 '21 at 07:54
  • Thank you @Chetan for your quick response. Unfortunately the same exception. – sonOfLiberty85 Jul 10 '21 at 08:06

1 Answers1

1

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.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • very well explained and it makes total sense. Yes, I definitely have a lot to learn in mocking. Thank you for sharing the moq quickstart. – sonOfLiberty85 Jul 10 '21 at 21:10
  • @sonOfLiberty85 glad it helped. It this resolves your original problem then you can mark it as answered. Happy coding. – Nkosi Jul 10 '21 at 23:22