4

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

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<> 参数的方法?

编辑:

所以如果我这样做:

cacheProvider.Expect(p => p.Get<MyBasicObject>("AnUniqueName", () => repo.GetByName("AnUniqueName"))).IgnoreArguments();

(也就是说,将 IgnoreArguments() 方法添加到 expect 调用的末尾)

...测试通过就好了。那么,我假设传入的参数有问题。在调用缓存提供程序方法的期望中,我做错了什么,但它阻塞了传入的匿名方法?

4

2 回答 2

1

问题是这两个匿名方法(其中一个Expect和创建的一个GetByName是两个不同的对象,因此不相等。您可以通过部分匹配这样的参数来解决这个问题:

cacheProvider.Expect(p => p.Get<MyBasicObject>(Arg<string>.Is.Equal("AnUniqueName"), Arg <Func<MyBasicObject>>.Is.NotNull));
于 2013-08-13T22:39:35.347 回答
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();
    }
}

这特别适用于我的用例(在缓存未命中的情况下调用数据库检索,并确保服务当时使用正确的存储库调用),但如果你'不打算立即调用匿名函数。我确信.WhenCalled 还有其他替代方案,但现在,这对我有用。

于 2013-08-14T01:40:28.410 回答