I'm having troubles with my testing IDBconnection Mock since it gives me a null database. Notice that for my IConfiguration instead of a mock I created a appsettingstest.json with connectionStrings to a database for testing purpouses. But for IDbConnection I don't know how to pass the ConnectionString since this is my first project with Dapper.
This is my handler constructor:
IDbConnection _dbConnection;
Context _context;
SigSettings _settings;
public SignalsHandler(IConfiguration configuration, IDbConnection connection)
{
_dbConnection = connection;
_settings = configuration.GetSection("SigSettings").Get<SigSettings>();
if (_settings == null)
_settings = new SigSettings();
}
And this is my test class constructor:
private Mock<IDbConnection> _connection = new Mock<IDbConnection>();
private readonly SignalsHandler _handler;
private readonly IConfiguration _configuration;
private readonly SigSettings _settings;
public SignalsTest()
{
_configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(@"appsettingstest.json", false, false)
.AddEnvironmentVariables()
.Build();
_connection.Setup(x => x.ConnectionString).Returns(path);
_settings = _configuration.GetSection("SigSettings").Get<SigSettings>();
if (_settings == null)
_settings = new SigSettings();
_handler = new SignalsHandler(_configuration, _connection.Object);
}
That works but when I do a test method, for example this dummy test:
public void CanGetAllSignals()
{
_connection.Setup(x => x.ConnectionString);
var result = _handler.GetSignals();
Assert.IsNotNull(result);
}
It calls this method:
public async Task<List<SignalsDTO>> GetSignals()
{
var res = new List<SignalsDTO>();
var sigList = await _dbConnection.QueryAsync<SigSignal>(_settings.Signals);
foreach (var s in sigList)
res.Add(new SignalsDTO(){IDTag = s.IDTag, Name = s.Name});
return res;
}
And here is where I have my problem because it gives me a NullReferenceException: 'Object reference not set to an instance of an object'
on this line: var sigList = await _dbConnection.QueryAsync<SigSignal>(_settings.Signals);
and if you look at the _dbConnection
you can see its a mocked object and that the Database is null, so that's the fail.
How can I fix this? I was trying to mock it but maybe that's not even the best approach.
CodePudding user response:
The problem is that the method is an extension method, not a method on the object itself. Depending on the mocking framework you use, there might be a way to mock extension methods too (update: kuldeep's answer shows a potential way to do that).
However, since you are using Dapper specifically, you can look at ready made solutions like https://github.com/UnoSD/Moq.Dapper for Moq.
It allows you to write a test like:
[Test]
public async Task QueryAsyncGeneric()
{
var connection = new Mock<DbConnection>();
var expected = new[] { 7, 77, 777 };
connection.SetupDapperAsync(c => c.QueryAsync<int>(It.IsAny<string>(), null, null, null, null))
.ReturnsAsync(expected);
var actual = (await connection.Object.QueryAsync<int>("", null, null, null, null)).ToList();
Assert.That(actual.Count, Is.EqualTo(expected.Length));
Assert.That(actual, Is.EquivalentTo(expected));
}
CodePudding user response:
you have to setup expectation on QueryAsync like following
this._connection
.Setup(s => s.QueryAsync<SigSignal>(
It.IsAny<Signals>())
.ReturnsAsync(yourFakeSigListWithTestData);
In It.IsAny() you should pass in the right object, i just put here Signals, but ideally it must be something of _settings.Signals type