I have written some tests using XUnit and Moq. One method of the mocked interface implementation is accepting a parameter of type Expression<Func<T, bool>>
Everything seems to be working well but I have trouble understanding the working of verifying that the method is called with the right expression.
Given the following test, the method does not return the value specified in the setup, even though the call seems correct.:
/// <summary>
/// Verify that a create fails appropriately when another entity was found given the same name,
/// Verify that the message of the exception contains the duplicate name
/// Verify that update fails before other calls are made
/// </summary>
[Theory(DisplayName = "Definition Types service - Create")]
[MemberData(nameof(DefinitionTypesTestData.SingleDefinitionType), MemberType = typeof(DefinitionTypesTestData))]
public async Task CreateDefinitionTypeShouldThrowDuplicateTest(DefinitionType obj)
{
if (obj == null) throw new NullReferenceException($"Test data was null in theory 'Definition Types service - Create'");
var crudService = new Mock<IEntityCrudService<DefinitionType>>();
crudService.Setup(crud => crud.GetEntitiesAsync(x => x.Name == obj.Name))
.Returns(Task.FromResult<IEnumerable<DefinitionType>>(new List<DefinitionType> {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
} }));
IDefinitionTypesService serviceUnderTest = new DefinitionTypesService(crudService.Object);
var exception = await Assert.ThrowsAsync<EntityDuplicationException>(() => serviceUnderTest.InsertDefinitionTypeAsync(obj));
Assert.Contains("Definition type", exception.DisplayMessage);
Assert.Contains(obj.Name, exception.DisplayMessage);
crudService.Verify(crud => crud.GetEntitiesAsync(x => x.Name == obj.Name), Times.Once);
crudService.VerifyNoOtherCalls();
}
I have the following implementation for InsertDefinitionType(DefinitionType obj):
async Task IDefinitionTypesService.InsertDefinitionTypeAsync(DefinitionType obj)
{
var definitiontypes = await _definitionTypeService.GetEntitiesAsync(x => x.Name == obj.Name);
if(definitiontypes.Any())
{
throw new EntityDuplicationException("Definition type", name: obj.Name);
}
try
{
await _definitionTypeService.CreateAsync(obj);
}
catch (EntityNotSavedException exc)
{
exc.EntityType = "Definition type";
throw exc;
}
}
When I change my setup as follows I do get the result, but in my verify function it says the function is never called (or at least with the given expression). :
crudService.Setup(crud => crud.GetEntitiesAsync(It.IsAny<Expression<Func<DefinitionType, bool>>>()))
.Returns(Task.FromResult<IEnumerable<DefinitionType>>(new List<DefinitionType> {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
} }));
Right now I have also changed the verification to be more generic:
crudService.Verify(crud => crud.GetEntitiesAsync(It.IsAny<Expression<Func<DefinitionType, bool>>>()), Times.Once);
Now my test passes, but I really want to verify the method is called correctly instead of being called at all. How do I solve this the easiest / best way?
To check if a method was called on a mocked object you can use the Mockito. verify method: Mockito. verify(someMock).
The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.
The simplest way to execute a method asynchronously is to start executing the method by calling the delegate's BeginInvoke method, do some work on the main thread, and then call the delegate's EndInvoke method. EndInvoke might block the calling thread because it does not return until the asynchronous call completes.
A synchronous method calls an async method, obtaining a Task . The synchronous method does a blocking wait on the Task .
You will need to be more specific about the expression used in the setup.
Use It.Is<T>()
and invoked the expression for the setup and verification.
[Theory(DisplayName = "Definition Types service - Create")]
[MemberData(nameof(DefinitionTypesTestData.SingleDefinitionType), MemberType = typeof(DefinitionTypesTestData))]
public async Task CreateDefinitionTypeShouldThrowDuplicateTest(DefinitionType obj) {
if (obj == null) throw new NullReferenceException($"Test data was null in theory 'Definition Types service - Create'");
//Arrange
var crudService = new Mock<IEntityCrudService<DefinitionType>>();
var list = new List<DefinitionType>() {
new DefinitionType {
Name = "Test",
Description = "Test",
DisplayName = "Test",
ID = Guid.NewGuid()
}
};
crudService
.Setup(_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj))))
.ReturnsAsync(list);
IDefinitionTypesService serviceUnderTest = new DefinitionTypesService(crudService.Object);
//Act
var exception = await Assert.ThrowsAsync<EntityDuplicationException>(() => serviceUnderTest.InsertDefinitionTypeAsync(obj));
//Assert
Assert.Contains("Definition type", exception.DisplayMessage);
Assert.Contains(obj.Name, exception.DisplayMessage);
crudService.Verify(_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj))), Times.Once);
crudService.VerifyNoOtherCalls();
}
Pay special attention to the expression used in the setup and verification.
_ => _.GetEntitiesAsync(It.Is<Expression<Func<DefinitionType, bool>>>(exp => exp.Compile()(obj)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With