Search code examples
c#unit-testingdelegatesrhino-mocks

Verify that correct method was passed in a function call


My test class takes 2 objects in its constructor, a data loader and a class that consumes the data returned from the data loader.

The data loader interface has 2 functions, LoadCompanies() and LoadEmployees(), both of which take an int parameter and return an IEnumerable.

How can I verify that the method under test passes LoadCompanies() and NOT LoadEmployees() into the data consumer class?

Here is my code:

[TestFixture]
public class TestingFunctionalParameters_UT
{
    [Test]
    public void Correct_Loader_Method_is_Used()
    {
        const int userId = 1;
        var companies = new[] { "c1", "c2" };
        var dataLoader = MockRepository.GenerateMock<ITestDataLoader>();
        var dataConsumer = MockRepository.GenerateMock<IDataConsumerClass>();

        var testObject = new TestClass(dataLoader, dataConsumer);

        dataConsumer.Expect(fc => fc.LoadIt(Arg<Func<IEnumerable<string>>>.Is.TypeOf)).Return(true);

        //TODO: validate that correct dataloader function was called...
        //dataLoader.Expect(dl => dl.LoadCompanies(userId)).Return(companies);

        var result = testObject.Run(userId);

        Assert.That(result, Is.True);
        dataLoader.VerifyAllExpectations();
        dataConsumer.VerifyAllExpectations();
    }
}

public class TestClass
{
    private readonly ITestDataLoader dataLoader;
    private readonly IDataConsumerClass funcClass;

    public TestClass(ITestDataLoader dataLoader, IDataConsumerClass funcClass)
    {
        this.dataLoader = dataLoader;
        this.funcClass = funcClass;
    }

    public bool Run(int userId)
    {
        Func<IEnumerable<string>> loadFn = () => dataLoader.LoadCompanies(userId);
        return funcClass.LoadIt(loadFn);
    }
}

public interface ITestDataLoader
{
    IEnumerable<string> LoadCompanies(int userId);
    IEnumerable<string> LoadEmployees(int userId);
}

public interface IDataConsumerClass
{
    bool LoadIt(Func<IEnumerable<string>> load);
}

Solution

  • (Edit: I am assuming that your example is a simplified one, and your actual implementation is an attempt to test a delegate injection pattern)

    Maybe you could write your test like this? (Edited to actually compile)

    [Test]
    public void Correct_Loader_Method_is_Used()
    {
        const int userId = 1;
        var companies = new[] { "c1", "c2" };
        var dataLoader = MockRepository.GenerateMock<ITestDataLoader>();
        var dataConsumer = MockRepository.GenerateMock<IDataConsumerClass>();
    
        var testObject = new TestClass(dataLoader, dataConsumer);
    
        dataConsumer.Expect(fc => fc.LoadIt(Arg<Func<IEnumerable<string>>>.Matches(x => x().Any()))).Return(true);
    
        //validate that correct dataloader function was called...
        dataLoader.Expect(dl => dl.LoadCompanies(userId)).Return(companies);
        // Fails if you uncomment this line
        //dataLoader.Expect(dl => dl.LoadEmployees(userId)).Return(companies);
    
        var result = testObject.Run(userId);
    
        Assert.That(result, Is.True);
        dataLoader.VerifyAllExpectations();
        dataConsumer.VerifyAllExpectations();
    }
    

    Basically the Matches() constraint will try execute the method, and if it tries to call LoadEmployees(), RhinoMocks will complain because it doesn't have a defined mock.

    Update: Handling Action<T> delegates

    This might be a little less robust, but for Action<T>s:

    public interface IDataConsumerClass
    {
        bool LoadIt(Func<IEnumerable<string>> load);
        bool ExecuteIt<T>(Action<T> execute);
    }
    
    //...
    
    dataConsumer.Expect(fc => fc.ExecuteIt(Arg<Action<int>>.Matches(x => ActionWrapper(x, userId)))).Return(true);
    
    //...
    
    private bool ActionWrapper<T>(Action<T> action, T arg)
    {
        action(arg);
        return true;
    }