I have a class, a service, and two interfaces:
public class MyBasicObject
{
public MyBasicObject() { }
public int Id { get; set; }
public string Name { get; set; }
}
public interface ICacheProvider
{
T Get<T>(string key, Func<T> fetcher) where T:class;
}
public interface IMyBasicObjectRepository
{
MyBasicObject GetByName(string name);
}
public class MyBasicObjectService
{
public MyBasicObjectService(ICacheProvider cacheProvider,
IMyBasicObjectRepository repository)
{
CacheProvider = cacheProvider;
MyBasicObjectRepository = repository;
}
public ICacheProvider CacheProvider { get; set; }
public IMyBasicObjectRepository MyBasicObjectRepository { get; set; }
public MyBasicObject GetByName(string name)
{
return CacheProvider.Get<MyBasicObject>(name, () =>
MyBasicObjectRepository.GetByName(name));
}
}
Using RhinoMocks, I'd like to be able to verify that when MyBasicObjectService.GetByName("AnUniqueName")
gets executed, so does CacheProvider.Get("AnUniqueName", () => MyBasicObjectRepository.GetByName("AnUniqueName"))
. I have a fixture set up like so:
[TestFixture]
public class MyBasicObjectServiceFixture
{
[Test]
public void GetByNameShouldCallCacheProviderFunction()
{
// Arrange
MockRepository mock = new MockRepository();
IMyBasicObjectRepository repo = mock.DynamicMock<IMyBasicObjectRepository>();
ICacheProvider cacheProvider = mock.DynamicMock<ICacheProvider>();
MyBasicObjectService service = new MyBasicObjectService(cacheProvider, repo);
cacheProvider.Expect(p => p.Get<MyBasicObject>("AnUniqueName", () => repo.GetByName("AnUniqueName")));
mock.ReplayAll();
// Act
var result = service.GetByName("AnUniqueName");
// Assert
mock.VerifyAll();
}
}
I would expect this test to pass, but when run, the assertion fails, notifying me that the function laid out in cacheProvider.Expect
is not being called. Am I missing something reg. mocking out and testing methods that take parameters of Func<>?
Edit:
So if I do:
cacheProvider.Expect(p => p.Get<MyBasicObject>("AnUniqueName", () => repo.GetByName("AnUniqueName"))).IgnoreArguments();
(that is to say, add the IgnoreArguments() method onto the end of the expect call)
...the test passes just fine. I'm assuming, then, it's a problem with the argument passed in. Is there something I'm doing wrong in the expect where the cache provider method is getting called but it chokes on the anonymous method getting passed in?
The problem is that the two anonymous methods (the one in the Expect
and the one which is created in GetByName
are two different objects and therefor are not equal. You can fix that by partially matching the arguments like this:
cacheProvider.Expect(p => p.Get<MyBasicObject>(Arg<string>.Is.Equal("AnUniqueName"), Arg <Func<MyBasicObject>>.Is.NotNull));