Search code examples
c#nunitmoq

How do I mock nested service call using moq


I have a statement similar to

var res = _serviceA.MethodA(() => _serviceB.MethodB(new objectA(){ Id = 10 }) 

which is being called twice in the method and also the response changes based on the value of Id, hence I need to setup the response such that a different object is returned based on the the Id value.

Current mock:

_serviceAMock.Setup(x => x.MethodA(It.IsAny<Func<ResponseObject>>())).Return(responseOfTypeResponseObject);

Is it possible to achieve this using moq? if yes how? I was able to mock MethodA and get the response but I couldn't figure out how to mock it such that the result varies based on the Id value.

Mocking Class:

public class ClassToTest
    {
        private readonly IServiceA<int> _serviceA;
        private readonly IServiceB _serviceB;

        public ClassToTest(IServiceA<int> serviceA, IServiceB serviceB)
        {
            _serviceA = serviceA;
            _serviceB = serviceB;
        }

        public void MethodToTest()
        {
            var res = _serviceA.MethodA(() => _serviceB.MethodB(new ObjectA() { Id = 10 }));
        }

    }

Supporting objects:

public class ObjectA
{
    public int Id { get; set; }
}

public interface IServiceB
{
    int MethodB(ObjectA objectA);
}

public interface IServiceA<T>
{
    T MethodA(Func<T> handler);
}

Solution

  • That worked for me:

    using FluentAssertions;
    using Moq;
    
    namespace MockDifferentResult;
    
    public class Tests
    {
        [Test]
        public void Test1()
        {
            // Arrange
            var serviceBMock = new Mock<IServiceB>();
            serviceBMock
                .Setup(service => service.MethodB(It.Is<ObjectA>(a => a.Id == 10)))
                .Returns(1);
            serviceBMock
                .Setup(service => service.MethodB(It.Is<ObjectA>(a => a.Id == 20)))
                .Returns(2);
            var serviceAMock = new Mock<IServiceA<int>>();
            serviceAMock
                .Setup(service => service.MethodA(It.IsAny<Func<int>>()))
                .Returns<Func<int>>(handler => handler());
            var testee = new ClassToTest(serviceAMock.Object, serviceBMock.Object);
            
            // Act
            testee.MethodToTest();
            
            // Assert
            testee.Res1.Should().Be(1);
            testee.Res2.Should().Be(2);
        }
    }
    
    public class ClassToTest
    {
        private readonly IServiceA<int> _serviceA;
        private readonly IServiceB _serviceB;
        
        public int Res1 { get; private set; }
        public int Res2 { get; private set; }
    
        public ClassToTest(IServiceA<int> serviceA, IServiceB serviceB)
        {
            _serviceA = serviceA;
            _serviceB = serviceB;
        }
    
        public void MethodToTest()
        {
            Res1 = _serviceA.MethodA(() => _serviceB.MethodB(new ObjectA { Id = 10 }));
            Res2 = _serviceA.MethodA(() => _serviceB.MethodB(new ObjectA { Id = 20 }));
        }
    }
    
    public class ObjectA
    {
        public int Id { get; set; }
    }
    
    public interface IServiceB
    {
        int MethodB(ObjectA objectA);
    }
    
    public interface IServiceA<T>
    {
        T MethodA(Func<T> handler);
    }
    

    Please give it a try and see if it suffices your needs.