模拟服务渠道
Mocking Service Channels
我正在为已经编写的代码编写一些单元测试。我 运行 遇到了一种情况,令人惊讶的是,我以前 运行 没有遇到过。
简而言之,我需要测试一个控制器,它通过 DI 获取服务依赖性,并在 Index 操作中对该服务调用一个方法以获取视图的 return 数据。
我的问题是我似乎无法模拟出服务依赖性。我试着搜索了一下,但找不到任何直接解决我的问题(或我缺乏理解)的东西。
控制器示例如下:
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);
}
}
这一切构建良好,但是当测试 运行s 我看到以下错误:
SetUp : System.NotSupportedException : Unsupported expression: service
=> service.GetSomeData(IsAny()) at Moq.MatcherFactory.CreateMatcher(Expression expression, Boolean
isParams) at Moq.MethodCall..ctor(Mock mock, Condition condition,
Expression originalExpression, MethodInfo method, Expression[]
arguments) at Moq.MethodCallReturn..ctor(Mock mock, Condition
condition, Expression originalExpression, MethodInfo method,
Expression[] arguments) at Moq.MethodCallReturn2..ctor(Mock mock,
Condition condition, Expression originalExpression, MethodInfo method,
Expression[] arguments) at
Moq.Mock.<>c__DisplayClass1c
2.b__1b() at
Moq.PexProtector.Invoke[T](Func1 function) at
Moq.Mock.Setup[T,TResult](Mock
1 mock, Expression1 expression,
Condition condition) at Moq.Mock
1.Setup[TResult](Expression`1
expression) at MyProj.Tests.Controllers.SomeControllerTests.Setup()
in path location
如有任何帮助,我们将不胜感激!
好吧,经过一些工作,我认为我想通了。我需要在我的 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;
为了更好,我将推迟将其标记为已回答,以查看是否会出现更好的结果,因为我无法为该函数指定输入参数。这对我来说不是问题,但将来可能会对某些人造成影响。
我正在为已经编写的代码编写一些单元测试。我 运行 遇到了一种情况,令人惊讶的是,我以前 运行 没有遇到过。
简而言之,我需要测试一个控制器,它通过 DI 获取服务依赖性,并在 Index 操作中对该服务调用一个方法以获取视图的 return 数据。
我的问题是我似乎无法模拟出服务依赖性。我试着搜索了一下,但找不到任何直接解决我的问题(或我缺乏理解)的东西。
控制器示例如下:
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);
}
}
这一切构建良好,但是当测试 运行s 我看到以下错误:
SetUp : System.NotSupportedException : Unsupported expression: service => service.GetSomeData(IsAny()) at Moq.MatcherFactory.CreateMatcher(Expression expression, Boolean isParams) at Moq.MethodCall..ctor(Mock mock, Condition condition, Expression originalExpression, MethodInfo method, Expression[] arguments) at Moq.MethodCallReturn..ctor(Mock mock, Condition condition, Expression originalExpression, MethodInfo method, Expression[] arguments) at 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](Func1 function) at Moq.Mock.Setup[T,TResult](Mock
1 mock, Expression1 expression, Condition condition) at Moq.Mock
1.Setup[TResult](Expression`1 expression) at MyProj.Tests.Controllers.SomeControllerTests.Setup() in path location
如有任何帮助,我们将不胜感激!
好吧,经过一些工作,我认为我想通了。我需要在我的 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;
为了更好,我将推迟将其标记为已回答,以查看是否会出现更好的结果,因为我无法为该函数指定输入参数。这对我来说不是问题,但将来可能会对某些人造成影响。