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);
}
(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;
}