Reputation: 555
I'm using Moq for mocking my objects in an ASP.NET Core project.
I want to mock the following IsConnection() method:
public Client(IMongoClient client)
{
_client = client;
}
public async Task<bool> IsConectionOk()
{
var pingCommand = new BsonDocument("ping", 1);
var mongoDb = _client.GetDatabase("Name");
var commandResult = await mongoDb.RunCommandAsync<BsonDocument>(pingCommand);
return commandResult != null;
}
As you see, there's only one injection, IMongoClient
, so I need to mock this one. Now, I need to mock IMongoDatabase
as well since the _client.GetDatabase
returns me an IMongoDatabase
which runs RunCommandAsync
this is my unit test:
[Fact]
public async Task IsConnectionOk_xxx_RunPing1Command()
{
var dbMock = new Mock<IMongoDatabase>();
var resultCommand = new BsonDocument("ok", 1);
dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<BsonDocument>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(resultCommand);
var mongoClientMock = new Mock<IMongoClient>();
mongoClientMock.Setup(stub => stub.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>())).Returns(dbMock.Object);
var client = new Client(mongoClientMock.Object);
var pingCommand = new BsonDocument("ping", 1);
//act
await client.IsConectionOk();
//assert
dbMock.Verify(mock => mock.RunCommandAsync<BsonDocument>( It.Is<BsonDocument>(x => x.Equals(pingCommand)) , It.IsAny<ReadPreference>() ,It.IsAny<CancellationToken>()));
}
You can see that I mocked a IMongoDatabase
so my mongoClientMock
can return it when the code is executing. When code is running, I have checked that mongoClientMock.GetDatabase()
is returning a MongoDatabase
(good until there), the problem is that when MongoDatabaseMock
calls RunCommandAsync is not returning what I set up, it just returns null. I don't know what I could be missing here, any thoughts?
Upvotes: 5
Views: 3821
Reputation: 247333
Things are a little tricky here.
Some background first.
According to documentation, IMongoDatabase.RunCommandAsync<TResult>
is defined as
Task<TResult> RunCommandAsync<TResult>(
Command<TResult> command,
ReadPreference readPreference = null,
CancellationToken cancellationToken = null
)
Note the Command<TResult>
, while in your code you pass a BsonDocument
.
Luckily BsonDocument
has an implicit conversion operator from BsonDocument
to Command<TResult>
When a setup does not get what was configured it tends to return null. So you need to make sure that it is setup properly so that it performs the expected behavior.
[TestClass]
public class UnitTest1 {
[TestMethod]
public async Task _IsConnectionOk_xxx_RunPing1Command() {
var dbMock = new Mock<IMongoDatabase>();
var resultCommand = new BsonDocument("ok", 1);
dbMock
.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<Command<BsonDocument>>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(resultCommand)
.Verifiable();
var mongoClientMock = new Mock<IMongoClient>();
mongoClientMock
.Setup(stub => stub.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>()))
.Returns(dbMock.Object);
var client = new Client(mongoClientMock.Object);
var pingCommand = new BsonDocument("ping", 1);
//act
var actual = await client.IsConectionOk();
//assert
Assert.IsTrue(actual);
dbMock.Verify();
}
}
Upvotes: 4
Reputation: 555
Just found my problem, take a look at the next line:
dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<BsonDocument>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(resultCommand);
turns out that RunCommandAsync
first parameter is a Command<TResult>
so the fix I needed was:
dbMock.Setup(stub => stub.RunCommandAsync<BsonDocument>(It.IsAny<Command<BsonDocument>>(), It.IsAny<ReadPreference>(), It.IsAny<CancellationToken>())).ReturnsAsync(anyResultCommand);
And problem solved!
Upvotes: 1