Unit testing 使用委托/lambda参数的存根方法调用

Unit testing 使用委托/lambda参数的存根方法调用,unit-testing,lambda,mocking,rhino-mocks,func,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 Exe

我有一个如下所示的接口和类:

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;
    }
}
public class ServiceConsumer
{
     public ServiceConsumer(IServiceFacade serviceFacade)
     {
         var returnInteger1 = serviceFacade.Execute(service => service.Method1("StringArgument1"));
         var returnInteger2 = serviceFacade.Execute(service => service.Method1("StringArgument2"));
     }
}
在我的单元测试中,我想将第一个调用的returnvalue存根为1,第二个调用的returnvalue存根为2

示例测试方法

[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);    

}
[测试]
公共void TestMethod()
{
var serviceFacadeStub=MockRepository.generateSub();

serviceFacadeStub.Stub(call=>call.Execute(Arg call.Execute)(Arg在大多数情况下,使用
Func
/
Action
模拟方法有点棘手(在我知道的任何模拟框架中…)

通常,您必须执行给定的
Func
/
操作
,然后结果应该会影响被测单元的其余部分

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

[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);

}
[测试]
公开无效测试方法(
{
var fakeService=MockRepository.generateSub();
存根(x=>x.Method1(“StringArgument1”)).Return(1);
存根(x=>x.Method1(“StringArgument2”)).Return(2);
var serviceFacadeStub=MockRepository.generateSub();
存根(call=>call.Execute(Arg.Is.Anything))
.WhenCalled(调用=>
{
var func=(func)invocation.Arguments[0];
invocation.ReturnValue=func(fakeService);
}).返回(0);
var shouldBeOne=serviceFacadeStub.Execute(service=>service.Method1(“StringArgument1”);
var shouldBeTwo=serviceFacadeStub.Execute(service=>service.Method1(“StringArgument2”);
断言.AreEqual(1,应该是1);
断言。等于(2,应为2);
}
我使用
fakeService
执行lambda,然后基于给定参数返回结果。
另一种选择是像你那样使用
匹配
,但是你必须使用反射来分析lambda…(它要复杂得多…)

如果其他人也有同样的问题,我会发布我的想法。我开始使用NSubstitute,这很简单

var serviceSub = Substitute.For<IService>();
serviceSub.Method1(Arg.Is<string>(arg => arg == "StringArgument1")).Returns(1);
serviceSub.Method1(Arg.Is<string>(arg => arg == "StringArgument2")).Returns(2);

var mobileServiceFacadeSub = Substitute.For<IServiceFacade>();
mobileServiceFacadeSub.Execute(Arg.InvokeDelegate<Func<IService, ICollection<TResult>>>(serviceSub));
var serviceSub=Substitute.For();
serviceSub.Method1(Arg.Is(Arg=>Arg==“StringArgument1”))。返回(1);
serviceSub.Method1(Arg.Is(Arg=>Arg==“StringArgument2”))。返回(2);
var mobileseservicefacadesub=替换为();
mobileseservicefacadesub.Execute(Arg.InvokeDelegate(serviceSub));