【问题标题】:Stub methodcalls with delegate / lambda parameters带有委托/ lambda 参数的存根方法调用
【发布时间】:2016-01-13 16:30:21
【问题描述】:

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

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。

示例测试方法

[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,但如果有更好的框架来做这件事,我愿意接受建议。

【问题讨论】:

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


    【解决方案1】:

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

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

    以下 sn-p 显示了解决问题的简单方法:

    [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......(它要复杂得多......)

    【讨论】:

      【解决方案2】:

      以防万一其他人有同样的问题,我会发布我的想法。我开始改用 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));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-03
        • 1970-01-01
        相关资源
        最近更新 更多