带有委托/lambda 参数的存根方法调用
Stub methodcalls with delegate / lambda parameters
我有一个界面 class 看起来像这样:
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 服务 运行,因此在 class.
中没有可用的该接口的实现实例
然后我像这样调用这个方法两次:
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。
示例测试方法
[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,但如果有更好的框架来做到这一点,我愿意接受建议。
在大多数情况下,使用 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,然后 return 基于给定参数的结果。
另一种选择是像你一样使用 Matches
,但是你必须使用反射来分析 lambda...(它要复杂得多....)
万一其他人遇到同样的问题,我会 post 我想出了什么。我开始改用 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));
我有一个界面 class 看起来像这样:
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 服务 运行,因此在 class.
然后我像这样调用这个方法两次:
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。
示例测试方法
[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,但如果有更好的框架来做到这一点,我愿意接受建议。
在大多数情况下,使用 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,然后 return 基于给定参数的结果。
另一种选择是像你一样使用 Matches
,但是你必须使用反射来分析 lambda...(它要复杂得多....)
万一其他人遇到同样的问题,我会 post 我想出了什么。我开始改用 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));