Search code examples
c#unit-testingmockingxunit

Unit testing and moq, best solution


I have the following scenario and I was wandering what is the proper way to test my services. I have 2 services and 2 repositories.

public class ServiceB : IServiceB
{
    public ServiceA(IRepoB)
    {
        
    }
    
    public async Task AuditInsert(param, param)
    {
        IRepoB.Insert(param, param)
    }
}


public class ServiceA : IServiceA
{
    public ServiceA(IRepoA, IServiceB)
    {
        
    }
    
    public async bool DoSomething(param)
    {
        //logic here
        
        IRepoA.Merge(param)
        IServiceB.AuditInsert(param, param)
    }
}


////// Testing part
public class ServiceATests
{
    private readonly ServiceA _sut;
    
    private readonly Mock<IRepoA> _repoA = new(MockBehavior.Strict)
    private readonly Mock<ServiceB> _serviceB = new(MockBehavior.Strict)
    
    _repoA.Setup(x => x.Merge(It.IsAny<ParamEntity>)).Return(Task.TaskCompleted)
    _serviceB.Setup(x => x.AuditInsert(It.IsAny<ParamEntity>, It.IsAny<ParamEntity>)).Return(Task.TaskCompleted)
    
    _sut = new ServiceA(_repoA.Object, _serviceB.Object)    
}

[Fact]
public async Task TestSomething()
{
    //arrange
    var testParam = {} // an object
    //act
    await _sut.DoSomething(testParam)
    
    //assert
    _repoA.Verify(x => x.Merge(), Times.Once)
    
    _serviceB.Verify(x => x.AuditInsert(It.IsAny<ParamEntity>, It.IsAny<ParamEntity>), Times.Once)  
}

The error I get on the act is "invocation failed with mock behaviour strict, all invocations on the mock must have a coresponding setup".

The code fails in ServiceA on the IServiceB.AuditInsert(param, param) line.

Probably is because when I setup ServiceB, I should somehow pass the mock of RepoB? But I do not know how to do that. Or is better if I remove the _serviceB.Verify part and just create a new class to test only the serviceB?

How should this dependency chain be tackeld on the testing part?

I am using xunit with Mock

I have created a small git repo with a project where the error can be replicated https://github.com/masterxfile/xUnitExample/tree/main/WebApplication1


Solution

  • The provided repro results in the following error:

    IAuditService.InsertAudit("test", "Yes") invocation failed with mock behavior Strict. Invocation needs to return a value and therefore must have a corresponding setup that provides it.

    Adding .Returns(Task.CompletedTask) to the corresponding mock fixes the issue:

    auditService.Setup(x => x.InsertAudit("test", "Yes"))
        .Returns(Task.CompletedTask);