Search code examples
c#unit-testinglambdaassertrhino-mocks

Checking the expected valued passed to a delegate using Rhino.Mocks


I am attempting to write a test case that will confirm that the value of a parameter passed into the method under test was used to invoke a delegate function that is passed as an argument to a method on a mocked service. The example below illustrates what I am doing:

The method under test:

public IList<IResultData> GetResultData(int id)
{
    Func<IExternalInterface, List<ExternalData> getDataMethod = client => client.GetExternalData(id);     
    List<ExternalData> externalDataList = serviceClient.ExecuteService(getDataMethod, "GetExternalData"); 

    var result = new List<ResultData>();

    //Some code to convert externalDataList into an IList<IResultData>

    return result;
}

The test method:

[TestMethod]
public void TestMethodCall()
{
    var mockServiceClient = MockRepository.GenerateMock<IServiceClient>();
    mockServiceClient.Expect(x => x.ExecuteService(
            Arg<Func<IExternalInterface, List<ExternalData>>.Is.NotNull,
            Arg<string>.Is.Equal("GetExternalData")));

    var myClass = new MyClass(mockServiceClient);

    var result = myClass.GetResultData(3);

    //Some assertions that result is as expected.
}

Is there a way to assert that the function passed into the Execute method is being passed the id of 3 from the test method's call to GetResultData()? The service being mocked is in a library not under my control so I can't change it's signature.


Solution

  • The following pattern will allow you to assert the lambda:

    [TestMethod]
    public void TestMethod1()
    {
        var wasCalled = false;
    
        var fakeService = MockRepository.GenerateStub<IExternalInterface>();
    
        fakeService.Stub(x => x.GetExternalData(1))
                   .Return(new List<ExternalData>() {new ExternalData() {Id = 1}});
    
        fakeService.Stub(service => service.ExecuteService(Arg<Func<IExternalInterface, 
                         List<ExternalData>>>.Is.Anything, Arg<string>.Is.Anything))
                   .WhenCalled(invocation =>
                   {
                       wasCalled = true;
                       var func = (Func<IExternalInterface, List<ExternalData>>) invocation.Arguments[0];
                       var res = func(fakeService);
    
                       //
                       // Assert here the "res"
                       //
    
    
                   }).Return(null);
    
        var target = new MyClass(fakeService);
    
        target.GetResultData(1);
    
        Assert. IsTrue(wasCalled);
    }
    

    However based you the code you've provided a better solution would be to use Do method as the following:

    [TestMethod]
    public void TestMethod1()
    {
        var fakeService = MockRepository.GenerateStub<IExternalInterface>();
    
        fakeService.Stub(x => x.GetExternalData(1)).Return(new List<ExternalData>() {new ExternalData() {Id = 1}});
    
        fakeService.Stub(service => service.ExecuteService(Arg<Func<IExternalInterface, 
                                                           List<ExternalData>>>.Is.Anything, Arg<string>.Is.Anything))
                   .Do(new Func<Func<IExternalInterface, List<ExternalData>>, string, List<ExternalData>>((func, str)=>func(fakeService)));
    
        var target = new MyClass(fakeService);
    
        var result = target.GetResultData(1);
    
        //
        // Assert here the "result"
        //
    
    }