表达式引用不属于嘲弄对象的方法 [英] Expression references a method that does not belong to the mocked object

查看:169
本文介绍了表达式引用不属于嘲弄对象的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个api服务调用另一个api服务。当我设置Mock对象时,它失败了一个错误:


NotSupportedException:表达式引用不属于嘲弄对象的方法


这是代码:

  private Mock< IEnumerable< ICarrierApiService< AccountSearchModel>>>> _mockCarrierService; 
private Mock< IApiService< AccountSearchModel>> _mockApiService;

[SetUp]
public void SetUp()
{
_mockApiService = new Mock< IApiService< AccountSearchModel>>();
_mockCarrierService = new Mock< IEnumerable< ICarrierApiService< AccountSearchModel>>>(gt;
_mockApiService.Setup(x => x.GetFromApiWithQuery(It.IsAny< string>()))。Returns(ApiValue());

//在.Select()中调用_mockApiService.GetFromApiWithQuery()
_mockCarrierService.Setup(x => x
.Select(s => s
.GetFromApiWithQuery(It.IsAny< string>()))ToList())
.Returns(new List< IQueryable< AccountSearchModel>> {ApiValue()});
}

我读了使用Moq进行的表示测试,但是对我来说没有效果。如果我删除这个 _mockCarrierService.Setup(),则测试用例可以运行,但由于没有使用 NullReferenceException t有一个有效的列表< IQueryable< AccountSearchModel>> 设置。



任何想法如何实现?






脚注:当前解决方案



FWIW,这是我目前使用的解决方案。

  private List< ICarrierApiService< AccountSearchModel>> _mockCarrierService; 
private AccountSearchController _mockController;
private Mock< ICarrierApiService< AccountSearchModel>> _mockApiService;

[SetUp]
public void SetUp()
{
_mockApiService = new Mock< ICarrierApiService< AccountSearchModel>>();
_carrierServiceMocks = new List< ICarrierApiService< AccountSearchModel>> {_mockApiService.Object};
_mockApiService.Setup(x => x.GetFromApiWithQuery(It.IsAny< string>()))。Returns(ApiValue());
_mockController = new AccountSearchController(_carrierServiceMocks);
}






脚注:另外,嘲笑框架



我还发现了一个商业模拟框架,支持嘲笑扩展方法,并链接到how-to文档: Telerik JustMock

解决方案

出现此问题是因为您试图模拟选择方法,这是一个扩展方法,而不是 IEnumerable< T>



基本上,没有办法模拟扩展方法。查看这个问题,了解您可能会发现有用的一些想法。



UPD(12/11/2014):



要更多地了解嘲笑扩展方法,请考虑以下几点:




  • 尽管扩展方法被调用,就像它们是扩展类型的实例方法一样,它们实际上只是一个静态方法


  • System.Linq 命名空间的扩展方法实现为纯函数 - 它们是确定性的,它们没有任何可观察的副作用。我同意静态方法是邪恶的,除了那些纯粹的功能 - 希望你也同意这个说法:)


  • 所以,给定一个类型为 T ,你将如何实现静态纯函数 f(T obj)?只有通过组合为对象 T (或任何其他纯函数实际))定义的其他纯函数,或通过读取不可变和确定性的全局状态(以保持函数 f 确定性和副作用 - 免费)。实际上,不变的和确定性的全球状态具有更方便的名称 - 一个常数。




所以,事实证明如果遵循静态方法应该是纯函数的规则(并且看起来像Microsoft遵循这个规则,至少对于LINQ方法),嘲笑扩展方法 f(this T obj) ,以嘲笑非扩展方法的非静态方法或状态 - 只是因为该扩展方法依赖于 obj 实例方法和状态(以及可能的其他纯函数和/或常量值)。



如果 IEnumerable< T> / code>, Select()扩展方法是实现,而 foreach 语句反过来使用 GetEnumerator )方法。所以你可以模仿 GetEnumerator(),并实现依赖它的扩展方法所需的行为。


I have an api service that calls another api service. When I set up the Mock objects, it failed with an error:

NotSupportedException: expression references a method that does not belong to the mocked object.

This is the code:

private Mock<IEnumerable<ICarrierApiService<AccountSearchModel>>> _mockCarrierService;
private Mock<IApiService<AccountSearchModel>> _mockApiService;

[SetUp]
public void SetUp()
{
  _mockApiService = new Mock<IApiService<AccountSearchModel>>();
  _mockCarrierService = new Mock<IEnumerable<ICarrierApiService<AccountSearchModel>>>();
  _mockApiService.Setup(x => x.GetFromApiWithQuery(It.IsAny<string>())).Returns(ApiValue());

  // Error occurred when call _mockApiService.GetFromApiWithQuery() in .Select()
  _mockCarrierService.Setup(x => x
            .Select(s => s
                .GetFromApiWithQuery(It.IsAny<string>())).ToList())
                .Returns(new List<IQueryable<AccountSearchModel>> { ApiValue() });
}

I read Expression testing with Moq but it didn't work for my case. If I remove this _mockCarrierService.Setup(), the test case can run but fails with a NullReferenceException because it didn't have a valid List<IQueryable<AccountSearchModel>> set up.

Any idea how I can achieve this?


Footnote: Current Solution

FWIW, here's the solution that I currently use. I am all ears for a better approach to the issue (until Moq starts supporting mocking extension methods).

private List<ICarrierApiService<AccountSearchModel>> _mockCarrierService;
private AccountSearchController _mockController;
private Mock<ICarrierApiService<AccountSearchModel>> _mockApiService;

[SetUp]
public void SetUp()
{
   _mockApiService = new Mock<ICarrierApiService<AccountSearchModel>>();
   _carrierServiceMocks = new List<ICarrierApiService<AccountSearchModel>> { _mockApiService.Object };
   _mockApiService.Setup(x => x.GetFromApiWithQuery(It.IsAny<string>())).Returns(ApiValue());
   _mockController = new AccountSearchController(_carrierServiceMocks);
}


Footnote: alternative mocking framework

I've also found a commercial mocking framework that supports mocking extension method and link to the how-to docs: Telerik JustMock.

解决方案

This problem occurs because you are trying to mock Select method, which is an extension method, not an instance method of IEnumerable<T>.

Basically, there is no way to mock an extension method. Have a look at this question for some ideas that you may find useful.

UPD (12/11/2014):

To gain more understanding on mocking extension methods, think about the following:

  • Although extension methods are called as if they were instance methods on the extended type, they are actually just a static methods with a bit of syntactic sugar.

  • Extension methods from System.Linq namespace are implemented as pure functions — they are deterministic and they don't have any observable side effects. I agree that static methods are evil, except those that are pure functions — hope you would agree with this statement too :)

  • So, given an object of type T, how would you implement static pure function f(T obj)? It is only possible by combining other pure functions that are defined for object T (or any other pure functions, actually), or by reading immutable and deterministic global state (to keep function f deterministic and side-effect-free). Actually, "immutable and deterministic global state" has more convenient name — a constant.

So, it turns out that if you follow the rule that static methods should be pure functions (and it looks like Microsoft follows this rule, at least for the LINQ methods), mocking an extension method f(this T obj) should be reducible to mocking non-static methods or state used by that extension method — simply because that extension method relies on the obj instance methods and state in its implementation (and possibly on the other pure functions and/or constant values).

In case of IEnumerable<T>, Select() extension method is implemented in terms of foreach statement which, in turn, uses GetEnumerator() method. So you can mock GetEnumerator() and achieve required behavior for extension methods that rely on it.

这篇关于表达式引用不属于嘲弄对象的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆