Reputation: 1214
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);
}
}
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
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