Stub方法使用delegate / lambda参数进行调用

时间:2016-01-13 16:30:22

标签: unit-testing lambda mocking rhino-mocks func

我有一个接口和类看起来像这样:

public interface IServiceFacade
{
     TResult Execute<TResult>(Func<IService, TResult> operation);
}

public class ServiceFacade : IServiceFacade
{
    private readonly string endpoint = "EndPoint";

    public TResult Execute<TResult>(Func<IService, TResult> operation)
    {
         // Call to remote WCF service that results in a TResult

         return TResult;
    }
}

IService接口表示远程运行的WCF服务,因此该类中没有此接口的实现实例。

我这样称呼这个方法两次:

public class ServiceConsumer
{
     public ServiceConsumer(IServiceFacade serviceFacade)
     {
         var returnInteger1 = serviceFacade.Execute(service => service.Method1("StringArgument1"));
         var returnInteger2 = serviceFacade.Execute(service => service.Method1("StringArgument2"));
     }
}

在我的单元测试中,我希望将第一个调用的返回值设为1,将第二个调用设为2。

示例testmethod

[Test]
public void TestMethod()
{
    var serviceFacadeStub = MockRepository.GenerateStub<IServiceFacade>();
    serviceFacadeStub.Stub(call => call.Execute(Arg<Func<IService, int>.Matches(?))).Return(1);     
    serviceFacadeStub.Stub(call => call.Execute(Arg<Func<IService, int>.Matches(?))).Return(2);

    var sut = new ServiceConsumer(serviceFacadeStub);    

}

我无法弄清楚要放入Matches的内容,或者最好不要使用匹配以外的内容。

现在我正在使用RhinoMocks和NUnit但是如果有一个更好的框架来做这个我可以接受建议。

2 个答案:

答案 0 :(得分:1)

在大多数情况下使用Func / Action模拟方法有点棘手(在我知道的任何模拟框架中......)

通常你必须执行给定的Func / Action,然后结果会影响被测单位的其余部分。

以下代码段显示了解决问题的简便方法:

[Test]
public void TestMethod(
{

    var fakeService = MockRepository.GenerateStub<IService>();
    fakeService.Stub(x => x.Method1("StringArgument1")).Return(1);
    fakeService.Stub(x => x.Method1("StringArgument2")).Return(2);

    var serviceFacadeStub = MockRepository.GenerateStub<IServiceFacade>();
    serviceFacadeStub.Stub(call => call.Execute(Arg<Func<IService, int>>.Is.Anything))
            .WhenCalled(invocation =>
            {
                var func = (Func<IService, int>)invocation.Arguments[0];
                invocation.ReturnValue = func(fakeService);
            }).Return(0);

    var shouldBeOne = serviceFacadeStub.Execute(service => service.Method1("StringArgument1"));
    var shouldBeTwo = serviceFacadeStub.Execute(service => service.Method1("StringArgument2"));

    Assert.AreEqual(1, shouldBeOne);
    Assert.AreEqual(2, shouldBeTwo);

}

我用fakeService执行lambda,然后根据给定的参数返回结果。 另一种选择是像你一样使用Matches,但是你必须使用反射来分析lambda ......(它要复杂得多......)

答案 1 :(得分:0)

只是因为其他人有同样的问题,我想出了什么。我开始使用NSubstitute而且很容易

<activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:windowSoftInputMode="adjustPan">