模拟服务渠道

时间:2016-06-08 20:12:26

标签: c# asp.net-mvc unit-testing nunit moq

我正在为已编写的代码编写一些单元测试。我遇到了一种情况,令人惊讶的是,我之前没有碰到过。

简而言之,我需要测试一个通过DI接受服务依赖的Controller,在Index操作中,在该服务上调用一个方法来返回视图的数据。

我的问题是我似乎无法模拟服务依赖。我尝试了一下,但找不到任何直接处理我的问题(或我缺乏理解)的东西。

以下是控制器的示例:

public partial class SomeController : Controller
{
    private readonly IServiceChannel<ISomeService> _someChannel;

    public SomeController(IServiceChannel<ISomeService> someChannel)
    {
        _someChannel= someChannel;
    }

    public virtual ActionResult Index()
    {
        var response = _someChannel.Fetch(someService => someService .GetSomeData(
            new GetSomeDataRequest
            {
                Id= StaticData.Id,
                All = true
            }
        ));

        var model = new IndexViewModel
        {
            AllData= response.AllData
        };

        return View(model);
    }
}

如您所见,DI注入一个IServiceChannel实例,该实例具有“Fetch”方法。然后,该方法允许您访问ISomeService,并从那里可以使用必要的参数调用接口上的任何方法。

我尝试使用以下逻辑编写测试:

[TestFixture]
public class SomeControllerTests
{
    private IServiceChannel<ISomeService> _someChannel;
    [SetUp]
    public void Setup()
    {
        var someChannelMoc = new Mock<IServiceChannel<ISomeService>>();
        someChannelMoc.Setup(
            i => i.Fetch(service => service.GetSomeData(It.IsAny<GetSomeDataRequest>())))
            .Returns(new GetSomeDataResponse());

        _someChannel= someChannelMoc.Object;
    }

    [Test]
    public void IndexTest()
    {
        var controller = new SomeController(_someChannel);
        var result = controller.Index();
        Assert.IsNotNull(result);
    }
}

这一切都很好,但是当测试运行时,我看到以下错误:

  

SetUp:System.NotSupportedException:不支持的表达式:service   =&GT; service.GetSomeData(IsAny())在Moq.MatcherFactory.CreateMatcher(表达式表达式,布尔值)   isParams)at Moq.MethodCall..ctor(Mock mock,Condition condition,   表达式originalExpression,MethodInfo方法,Expression []   参数)在Moq.MethodCallReturn..ctor(Mock mock,Condition   condition,表达式originalExpression,MethodInfo方法,   表达式[]参数)在Moq.MethodCallReturn 2..ctor(Mock mock, Condition condition, Expression originalExpression, MethodInfo method, Expression[] arguments) at Moq.Mock.<>c__DisplayClass1c 2.b__1b()at   Moq.PexProtector.Invoke [T](Func 1 function) at Moq.Mock.Setup[T,TResult](Mock 1 mock,Expression 1 expression, Condition condition) at Moq.Mock 1.Setup [TResult](Expression`1   表达式)在MyProj.Tests.Controllers.SomeControllerTests.Setup()   在路径位置

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

好吧,经过一些工作,我我想通了。我需要匹配IServiceChannel实现中的函数参数:

public TResult Fetch<TResult>(Func<T, TResult> block)
{ ... }

所以现在我的测试设置改为看起来像这样:

 var someChannelMoc = new Mock<IServiceChannel<ISomeService>>();
            someChannelMoc.Setup(i => i.Fetch(It.IsAny<Func<ISomeService,GetSomeDataResponse>>()))
                .Returns(()=>new GetSomeDataResponse{AllData= new List<Data>()});

            _someChannel = someChannelMoc.Object;

为了更好的事情,我会不断标记这个作为回答,看看是否有更好的东西出现,因为我无法指定该功能的输入参数。对我来说这不是问题,但可能是将来的某个人。