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

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

问题描述

我有调用另一个API服务的API服务。当我设置了模拟对象,它失败,出现错误:

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

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

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

这是代码:

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() });
}



我读的Expression测试与起订量但它并没有对我的情况下工作。如果我删除此 _mockCarrierService.Setup(),测试用例可以运行,但失败了的NullReferenceException ,因为它没'吨有一个有效的列表与LT; IQueryable的< AccountSearchModel>> 成立。

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.

任何想法,我怎么能做到这一点?

脚注:目前的解决方案

FWIW,这里是我目前使用的解决方案。的我是一个更好的方法所有的耳朵的问题(直到起订量开始支持嘲讽扩展方法)。

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);
}






脚注:替代模拟框架

我还发现一个商业嘲弄的框架,支持嘲讽扩展方法,并链接到如何对文档:的Telerik JustMock

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

推荐答案

发生此问题,因为你试图嘲弄选择的方法,这是一个的扩展方法,而不是的IEnumerable<的实例方法; T>

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(2014年12月11日):

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.

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

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 :)

所以,给定类型的对象 T ,你将如何实现静态纯函数 F(T OBJ)?它是唯一可能通过 T (或任何其他纯函数,实际上),或通过阅读不可改变的,确定性的全局状态结合了为对象定义其它纯函数(保持功能˚F确定性和副作用免费)。其实,不可改变的,确定性的全局状态有更方便的名字 - 恒定

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.

所以,事实证明,如果你按照规则,静态方法应该是纯功能(它看起来像微软遵守这一规则,至少在LINQ方法),嘲讽扩展方法 F(这件T OBJ)应该归结为嘲讽通过扩展方法使用非静态方法或状态的 - 仅仅是因为该扩展方法依赖于 OBJ 实例在其实施方式和状态(以及可能的其它纯的功能和/或常数值)

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).

的IEnumerable&所述的情况下; T> 选择()扩展方法是的的foreach 语句来实现的,反过来,使用的GetEnumerator() 方法。所以,你可以嘲笑的GetEnumerator()并实现依赖于它的扩展方法要求的行为。

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天全站免登陆