使用参数中的匿名函数验证函数调用

时间:2013-08-13 21:08:23

标签: c# rhino-mocks anonymous-function

我有一个类,一个服务和两个接口:

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调用的末尾)

......测试通过就好了。我假设,这是传入的参数的一个问题。是否有一些我在调用缓存提供程序方法的时候会出错,但它会在传入的匿名方法上窒息?

2 个答案:

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

这特别适用于我的用例(在高速缓存未命中的情况下调用数据库检索,并确保服务在那时使用正确的存储库调用),但这是一种不那么好的解决方法如果您不打算立即调用匿名函数。我确信还有其他选择。当时,但是现在,这对我有用。