Unit tests not showing code coverage with async/await - c#

I'm using vs2017 and none of my unit tests are showing code coverage. I"m using async/await and MOQ.
[TestMethod]
[TestCategory("SeriesRepository")]
public void GetSeriesAsyncShouldReturnSeriesId12345()
{
var repositoryMock = new Mock<ISeriesRepository>();
var seriesId = "12345";
var channel = 75864;
var mockSeries = new Mock<ISeries>();
mockSeries.SetupGet(x => x.SeriesId).Returns("12345");
repositoryMock
.Setup(x => x.GetSeriesAsync(seriesId, channel))
.ReturnsAsync(mockSeries.Object);
var result = repositoryMock.Object.GetSeriesAsync(seriesId, channel).Result;
result.SeriesId.Should().Be(seriesId);
}

First fact is that you are not actually testing anything in your test as you simply create mocks and invoke the mocks.
You are simply testing that the mocking framework works as advertised.
Secondly the tests can be made async as well to allow the test to exercise sequentially.
[TestMethod]
[TestCategory("SeriesRepository")]
public async Task GetSeriesAsyncShouldReturnSeriesId12345() {
var repositoryMock = new Mock<ISeriesRepository>();
var seriesId = "12345";
var channel = 75864;
var mockSeries = new Mock<ISeries>();
mockSeries.Setup(_ => _.SeriesId).Returns(seriesId);
repositoryMock
.Setup(_ => _.GetSeriesAsync(seriesId, channel))
.ReturnsAsync(mockSeries.Object);
var result = await repositoryMock.Object.GetSeriesAsync(seriesId, channel);
result.SeriesId.Should().Be(seriesId);
}
What is suppose to happen is that you mock the dependencies of a target under test to behave as expected in order to verify some desired behavior
Lets say we wanted to test a target method of a class. Something like
public class SeriesService {
private readonly ISeriesRepository repository;
public SeriesService(ISeriesRepository repository
this.repository = repository;
}
public async Task<ISeries> GetSeries(string seriesId, int channel) {
var series = await repository.GetSeriesAsync(seriesId, channel);
//...do some other stuff
return series;
}
}
An example test would then look like this
[TestMethod]
[TestCategory("SeriesRepository")]
public async Task TargetMethodShouldReturnSeriesId12345() {
//Assert
var repositoryMock = new Mock<ISeriesRepository>();
var seriesId = "12345";
var channel = 75864;
var mockSeries = new Mock<ISeries>();
mockSeries.Setup(_ => _.SeriesId).Returns(seriesId);
repositoryMock
.Setup(_ => _.GetSeriesAsync(seriesId, channel))
.ReturnsAsync(mockSeries.Object);
var target = new SeriesService(repositoryMock.Object);
//Act
var result = await target.GetSeries(seriesId, channel);
//Assert
result.Should().NotBeNull();
result.SeriesId.Should().Be(seriesId);
}

There isn't any wait for your repositoryMock setup to complete. So, your test case is ending before your async calls are complete.
Make sure you wait by adding:
repositryMock.setup(...).ReturnsAsync(...).GetAwaiter().GetResult();
Or
repositryMock.setup(...).ReturnsAsync(...).Result;
Or
repositryMock.setup(...).ReturnsAsync(...).Wait();
This should solve your problem.

Related

SonarQube states "lines not covered" but they are covered by UnitTests (MediatR Handle)

I'm facing a problem with SonarQube and I think it has to do with the Handle function of MediatR in C#.
Here is the handle function which SonarQube says is not covered by tests
But this function is tested by these two unit tests:
[Fact]
public async Task SpeichereBetriebCommandHandler_SollteGuidZurueckgeben_WennBetriebNichtExistiert()
{
// Arrange
Fixture fixture = new Fixture();
var speichereBetriebCommand = fixture.Build<SpeichereBetriebCommand>().Create();
// Act
var result = await _speichereBetriebCommandHandler.Handle(speichereBetriebCommand, new System.Threading.CancellationToken());
// Assert
result.Should().NotBe(String.Empty);
}
[Fact]
public async Task SpeichereBetriebCommandHandler_SollteLeerStringZurueckgeben_WennBetriebExistiert()
{
// Arrange
Fixture fixture = new Fixture();
var someData .....
var betrieb = fixture.Build<BetriebDto>()
.With(b => b.SomeData, someData )
.
.
.
.Create();
var speichereBetriebCommand = fixture.Build<SpeichereBetriebCommand>()
.With(b => b.SomeData, someData)
.
.
.
.Create();
await _betriebRepository.AddAsync(betrieb);
await _statistikContextRepository.SaveChangesAsync();
// Act
var result = await _speichereBetriebCommandHandler.Handle(speichereBetriebCommand, new System.Threading.CancellationToken());
// Assert
result.Should().Be(String.Empty);
}
I've also debugged the unit tests and both land in the handle function. So I've tested the complete function. Why does SonarQube not agree with me?
The issue has been resolved. The root cause was that I was utilizing XUnit, but there were still some NUnit references present in my .csproj file. This caused the tests to not execute properly in the pipeline.

Redis StringSetAsync returns false in Unit Tests using Moq

I am currently writing unit tests for a RedisProvider Class for my Solution. I have a method in my class that sets a key in the Redis Cache:
public async Task<bool> StringSetAsync(string key, string value)
{
var cache = multiplexer.GetDatabase();
//Some other stuff
result = await cache.StringSetAsync(key, value);
return result;
}
In my unit tests I have the following setup:
var mockMultiplexer = new Mock<IConnectionMultiplexer>();
mockMultiplexer.Setup(_ => _.IsConnected).Returns(true);
mockMultiplexer.Setup(_ => _.Configuration).Returns(MockedData.CacheConnectionString);
var mockDatabase = new Mock<IDatabase>();
mockMultiplexer
.Setup(_ => _.GetDatabase(It.IsAny<int>(), It.IsAny<object>()))
.Returns(() => mockDatabase.Object);
RedisCacheProvider mockedCacheProvider = new RedisCacheProvider(new Mock<ILogger<RedisCacheProvider>>
().Object, mockMultiplexer.Object);
var result = await mockedCacheProvider.StringSetAsync(It.IsAny<string>(), It.IsAny<string>());
When I run the above code for my unit test, the result that I receive is always false. Is there a way to get a true result? What is wrong over here?
I realized that this should be mocked by the services using the class rather than validating this on the class itself.
Here you go:
mockedCacheProvider.Setup(h => h.StringSetAsync(
It.IsAny<string>(),
It.IsAny<string>())).ReturnsAsync(() => true);

Unit test pass string argument any string value except null or empty

I am unit testing controller logic. I have a controller action which takes a string parameter like so:
public async Task<IActionResult> Get(string searchCriterion)
{
if (string.IsNullOrEmpty(searchCriterion))
{
// Log modelstate errors
return BadRequest("Hello");
}
// etc...
}
Please note the guard which checks for string.IsNullOrEmpty(searchCriterion).
In my unit tests I like to use It.IsAny<string>():
// Act
var result = await controller.GetSearchNetworkAsync(It.IsAny<string>());
The guard means I cannot use this because It.IsAny<string>() means that the test string could indeed by null ot empty.
My question is: can I pass the argument, in my unit test, that corresponds to "any string value except null or empty"?
Edit
Please find the full unit test...
[Fact]
public async Task GetSearchNetworkAsync_ReturnsOkWithNetworkListViewModelCollection_Rn()
{
// Arrange
var mockRepo = new Mock<IUserRepository>();
mockRepo.Setup(repo => repo.GetUserAndNetworkAsync(It.IsAny<string>()))
.ReturnsAsync(GetOwnUserProfile());
mockRepo.Setup(repo => repo.SearchBirdersToFollowAsync(It.IsAny<ApplicationUser>(), It.IsAny<string>(), It.IsAny<IEnumerable<string>>()))
.ReturnsAsync(GetListOfApplicationUsers(3));
var mockUnitOfWork = new Mock<IUnitOfWork>();
var controller = new UserController(_mapper, mockUnitOfWork.Object, _logger.Object, mockRepo.Object);
controller.ControllerContext = new ControllerContext()
{
HttpContext = new DefaultHttpContext() { User = GetTestClaimsPrincipal() }
};
// Act
//var result = await controller.GetSearchNetworkAsync(It.IsAny<string>());
var result = await controller.GetSearchNetworkAsync(It.Is<string>(str => !string.IsNullOrEmpty(str)));
// Assert
var objectResult = result as ObjectResult;
Assert.NotNull(objectResult);
Assert.IsType<OkObjectResult>(result);
Assert.True(objectResult is OkObjectResult);
Assert.Equal(StatusCodes.Status200OK, objectResult.StatusCode);
Assert.IsType<List<NetworkUserViewModel>>(objectResult.Value);
var model = objectResult.Value as List<NetworkUserViewModel>;
Assert.Equal(3, model.Count);
}
It.IsAny<string>() is meant to be used only as part of the setup for mocks.
mock.Setup(_ => _.SomeMember(It.IsAny<string>()).Returns(SomeValue);
It is not meant to be used outside of the Setup expression and will return the default value for the provided generic argument.
ie
It.IsAny<string>() == null
Use an actual string to pass the desired value into your subject under test.
//Arrange
//...
string searchCriterion = "Any String You Want Here";
// Act
var result = await controller.GetSearchNetworkAsync(searchCriterion);
What are you trying to test? If the test is not checking the guard then pass an expected string value
[Fact]
public async Task GetSearchNetworkAsync_WithValidString_ReturnsOkWithNetworkListViewModelCollection_Rn()
{
...
// Act
var result = await controller.GetSearchNetworkAsync("some value");
You would then have an different test to check for the guard
[Fact]
public async Task GetSearchNetworkAsync_WithNullString_ReturnsBadRequest()
{
...
// Act
var result = await controller.GetSearchNetworkAsync(null);
or
[Fact]
public async Task GetSearchNetworkAsync_WithEmptyString_ReturnsBadRequest()
{
...
// Act
var result = await controller.GetSearchNetworkAsync(string.empty);

How to Mock IMongoDatabase

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?
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();
}
}
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!

Mocking Method Execution Times and Sequence

I am using Moq paired with an Interface of methods. I need to test that the methods in this interface are executed in a certain sequence as well as a certain number of times for each one.
Interface
public interface IInterface
{
void MethodOne(string foo);
void MethodTwo(string foo);
}
Method
// MyClass stuff ...
public async Task Run()
{
MethodOne("foo");
MethodTwo("foo");
}
// ...
Tests
I've written this test to verify that the methods are only executed a certain amount of times (once):
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.Verify(i=> i.MethodOne("foo"), Times.Once());
mock.Verify(i=> i.MethodTwo("foo"), Times.Once());
}
This works fine...
I've tried these tests for determining a certain sequence is properly met, but the test seems to always pass.
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo"));
}
Should pass, and does...
[TestMethod]
public async Task Test()
{
var mock = new Mock<IInterface>();
var mockSequence = new MockSequence();
var obj = new MyClass();
await obj.Run();
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
}
Should not pass, but does...
What do I need to do differently to verify proper sequence is met?
How do I combine the two so that I can test number of execution times AND proper sequence?
Your example tests for InSequence seem to be in the wrong order. You should be performing the Setup, before you invoke the Run method. I've assumed this is a typo and that your actual tests do the Setup, then invoke the object in the correct order. It's also not clear how your mock of IInterface gets to MyClass. In my final example, I've assumed it's actually injected...
Moq's InSequence support only seems to work if you're using strict mocks. If you create your Mock like this:
var mock = new Mock<IInterface>(MockBehavior.Strict);
Then this will work:
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo"));
while this fails:
mock.InSequence(mockSequence).Setup(i => i.MethodTwo("foo")); // swapped order here
mock.InSequence(mockSequence).Setup(i => i.MethodOne("foo"));
Note, the error that comes is about the method missing a corresponding setup... rather than it being called out of sequence, which isn't necessarily the easiest to decode if you're not expecting it.
The alternate approach, if you don't want to / can't use strict mocks is to implement your own sequence checking using callbacks. Something like this:
int sequence = 1;
mock.Setup(i => i.MethodOne("foo"))
.Callback(()=>Assert.AreEqual(1, sequence++, "Method called out of sequence"));
mock.Setup(i => i.MethodTwo("foo"))
.Callback(() => Assert.AreEqual(2, sequence++, "Method called out of sequence"));
var obj = new MyClass(mock.Object);
await obj.Run();
This may be further off topic than you want to go but NSubstitute is a great mocking library that handles this very well.
In NSubstitute it's just:
var mock = Substitute.For<IInterface>();
var obj = new MyClass();
await obj.Run();
Received.InOrder(() => {
mock.MethodOne("foo");
mock.MethodTwo("foo");
});

Categories

Resources