Hammas
Hammas

Reputation: 1214

C# xUnit test actual values returned are empty

I'm trying to write unit test using xUnit for EntityService class which is using Dapper to get data from Sqllite database. In my unit test it always returns actual values as List<Entity> [] and test fails. I'm not understanding what I am missing here.

Test Class

public class EntityServiceTests
{
    private readonly IEntityService _sut;
    private readonly Mock<IEntityService> _entityServiceMock;

    public EntityServiceTests()
    {
        _entityServiceMock = new Mock<IEntityService>();

        var dapperMock = new Mock<IDapperWrapper>();
        _sut = new EntityService(dapperMock.Object);
    }

    [Fact]
    public void GetEntities_ShouldReturnEntities()
    {
        //Arrange
        var expectedEntities = new List<Entity>
        {
            new()
            {
                Id = 1,
                Name = "Test",
                X = 12,
                Y = 14.5,
                CoordId = 1
            },
            new()
            {
                Id = 2,
                Name = "Test2",
                X = 16,
                Y = 18.5,
                CoordId = 2
            }
        };

        var query = @"SELECT ent.*, crd.x, crd.y, crd.id as CoordId 
                            FROM entities ent 
                            INNER JOIN coords crd ON crd.entityId = ent.Id";

        _entityServiceMock.Setup(x => x.GetEntities(0)).Returns(expectedEntities);

        //Act
        var entities = _sut.GetEntities(0).ToList();

        //Assert

        Assert.Equal(expectedEntities, entities);
    }
}  

Service Class

public class EntityService : IEntityService
{
    private readonly IDapperWrapper _dapperWrapper;

    public EntityService(IDapperWrapper dapperWrapper)
    {
        _dapperWrapper = dapperWrapper;
    }

    public IEnumerable<Entity> GetEntities(int entityId)
    {
        var query = @"SELECT ent.*, crd.x, crd.y, crd.id as CoordId 
                            FROM entities ent 
                            INNER JOIN coords crd ON crd.entityId = ent.Id ";
        if (entityId > 0)
        {
            query += " WHERE ent.id = @id";

            var entities = _dapperWrapper.Query<Entity>(query, new { id = entityId });
            return entities;
        }
        else
        {
            var entities = _dapperWrapper.Query<Entity>(query);

            return entities;
        }
    }
}  

Dapper Wrapper Class

public class DapperWrapper : IDapperWrapper
{
    private IDbConnection Connection { get; }

    public DapperWrapper()
    {
        Connection = new SQLiteConnection(GetConnectionString("ConnectionString"));
    }

    private string GetConnectionString(string name)
    {
        return ConfigurationManager.ConnectionStrings[name].ConnectionString;
    }

    public IEnumerable<T> Query<T>(string query)
    {
        return Connection.Query<T>(query);
    }

    public IEnumerable<T> Query<T>(string query, object param)
    {
        return Connection.Query<T>(query, param);
    }

    public T QuerySingle<T>(string query, object param)
    {
        return Connection.QuerySingle<T>(query, param);
    }
}  

Unit test result

Normally the project is working fine. but in Test it fails. I think i'm missing something very basic but crucial.

UPDATE: I'm using this code now but still getting failed result

    [Fact]
    public void GetEntities_Should_Return_All_Entities_If_0_Is_Provided_In_Param()
    {
        //Arrange
        var expectedEntities = new List<Entity>
        {
            new()
            {
                Id = 1,
                Name = "Test",
                X = 12,
                Y = 14.5,
                CoordId = 1
            },
            new()
            {
                Id = 2,
                Name = "Test2",
                X = 16,
                Y = 18.5,
                CoordId = 2
            }
        };

        var query = @"SELECT ent.*, crd.x, crd.y, crd.id as CoordId 
                        FROM entities ent 
                        INNER JOIN coords crd ON crd.entityId = ent.Id ";

        var dapperMock = new Mock<IDapperWrapper>();
        dapperMock.Setup(x => x.Query<Entity>(query)).Returns(expectedEntities);
        var sut = new EntityService(dapperMock.Object);

        //Act
        var entities = sut.GetEntities(0);

        //Assert
        Assert.Equal(expectedEntities, entities);
    }

Upvotes: 4

Views: 1252

Answers (1)

mu88
mu88

Reputation: 5404

I think i'm missing something very basic but crucial.

Indeed 🙂 mocking is intended to be used to mock away the dependencies from a unit to test (sut). In your case your unit to test is the EntityService and the dependency to mock away is IDapperWrapper.
But instead of only mocking the dependency, you're mocking the SUT as well with _entityServiceMock.

So you COULD try to do it like this within your test:

public class EntityServiceTests
{
    [Fact]
    public void GetEntities_ShouldReturnEntities()
    {
        //Arrange
        var expectedEntities = new List<Entity>
        {
            new()
            {
                Id = 1,
                Name = "Test",
                X = 12,
                Y = 14.5,
                CoordId = 1
            }
        };

        var query = @"SELECT ent.*, crd.x, crd.y, crd.id as CoordId 
                            FROM entities ent 
                            INNER JOIN coords crd ON crd.entityId = ent.Id WHERE ent.id = @id";
        var dapperMock = new Mock<IDapperWrapper>();
        dapperMock.Setup(x => x.Query<Entity>(query, 1)).Returns(expectedEntities.First());
        var sut = new EntityService(dapperMock.Object);

        //Act
        var entities = sut.GetEntities(1).ToList();

        //Assert
        Assert.Equal(expectedEntities, entities);
    }
}  

But I highly discourage you from doing so because you'll end up mocking all the Dapper stuff.

Instead you better use an in-memory database (like SQLite), use a real Dapper instance. This way your tests will become much more comprehensive, shorter and business-facing. This blog post should give you a good starting point.

Upvotes: 2

Related Questions