我有一个类,一个服务和两个接口:
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));
}
}
使用RhinoMocks,我希望能够验证MyBasicObjectService.GetByName("AnUniqueName")
何时执行,CacheProvider.Get("AnUniqueName", () => MyBasicObjectRepository.GetByName("AnUniqueName"))
也是如此。我有一个这样的夹具设置:
[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();
}
}
我希望这个测试能够通过,但是当运行时,断言失败,通知我cacheProvider.Expect
中列出的函数没有被调用。我错过了什么。模拟和测试采用Func&lt;&gt;参数的方法
编辑:
所以,如果我这样做:
cacheProvider.Expect(p => p.Get<MyBasicObject>("AnUniqueName", () => repo.GetByName("AnUniqueName"))).IgnoreArguments();
(也就是说,将IgnoreArguments()方法添加到expect调用的末尾)
......测试通过就好了。我假设,这是传入的参数的一个问题。是否有一些我在调用缓存提供程序方法的时候会出错,但它会在传入的匿名方法上窒息?
答案 0 :(得分:1)
问题是两个匿名方法(Expect
中的一个和GetByName
中创建的方法是两个不同的对象,因此不相等。你可以通过部分匹配来解决这个问题。像这样的论点:
cacheProvider.Expect(p => p.Get<MyBasicObject>(Arg<string>.Is.Equal("AnUniqueName"), Arg <Func<MyBasicObject>>.Is.NotNull));
答案 1 :(得分:0)
我最终为测试做的是:
[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>(Arg<string>.Is.Equal("AnUniqueName"), Arg<Func<MyBasicObject>>.Is.NotNull))
.WhenCalled(call =>
{
var repoCall = (Func<MyBasicObject>)call.Arguments[1];
repoCall.Invoke();
});
repo.Expect(c => c.GetByName("AnUniqueName"));
mock.ReplayAll();
// Act
var result = service.GetByName("AnUniqueName");
// Assert
mock.VerifyAll();
}
}
这特别适用于我的用例(在高速缓存未命中的情况下调用数据库检索,并确保服务在那时使用正确的存储库调用),但这是一种不那么好的解决方法如果您不打算立即调用匿名函数。我确信还有其他选择。当时,但是现在,这对我有用。