在 VS15 中使用 Moq 进行单元测试时,Returnsasync(null) 会引发构建错误

问题描述 投票:0回答:3

当我在 Visual Studio 中的 C# 单元测试方法中使用

ReturnsAsync(null)
(使用
Moq
)时,出现错误:

“以下方法或属性之间的调用不明确”

然后是具有不同参数的

ReturnsAsync
方法列表。据我所知,这是由于
ReturnsAsync
函数超载造成的。但是,当我在同事的计算机上运行相同的单元测试时,它运行时没有任何错误。有谁知道为什么会发生这种情况?有谁知道如何解决这个问题吗?

此外,当我构建时,我收到警告:

所有引用 ******** 的包都必须安装 nuget 包 Microsoft.Bcl.Build。

有效果吗?

c# unit-testing asynchronous moq
3个回答
89
投票

Moq

ReturnsAsync
类中有两个
ReturnsExtensions
扩展方法。它们具有以下参数:

(this IReturns<TMock, Task<TResult>> mock, TResult value)
(this IReturns<TMock, Task<TResult>> mock, Func<TResult> valueFunction)

如您所见,一个接受任务应返回的值,另一个接受将返回值的委托。当您传递

null
时,编译器不知道它是值还是委托。当任务参数是值类型(例如 int)时,情况并非如此。因为它不能为 null,并且编译器知道 null 是委托。你同事的电脑可能就是这种情况。

要修复此错误,您需要帮助编译器选择正确的方法重载 - 将 null 转换为任务结果的类型(例如字符串):

RetursAsync((string)null)

或者你可以传递 null 值

string s = null;
... ReturnsAsync(s);

14
投票

问题是编译器根据方法参数的类型和传递的参数类型来选择调用哪个重载方法。这称为“方法重载解析”。但字面意思是“没有值”,同时它本身不携带任何类型信息。如果没有类型,编译器不知道要调用哪个重载方法,因此它会抱怨“

调用不明确
”。 如果您传递文字 null 而不是 "Hello world"

,您(编译器)就知道它有一个值(文本“Hello world”)并且它是

null

 类型。但在 
string
 的情况下,类型信息丢失 - 它可能是没有值的字符串、没有值的委托,或者例如没有值的自定义引用类型。
正如 
Sergey 提到的
,有两个重载方法:

null

它们都有一个参数,第一个参数为 (this IReturns<TMock, Task<TResult>> mock, TResult value) (this IReturns<TMock, Task<TResult>> mock, Func<TResult> valueFunction)

类型,第二个参数为
TResult
类型。没有类型信息的

Func<TResult>

 可能是两者/其中任何一个,所以你只需要提示编译器调用哪一个。
您有两个选择:

null

值链接到某种类型并调用重载接受

null
  • 传递一个返回 
    TResult
     的函数,即调用接受 
    null
  • 的重载
    对我来说,最简单的解决方案是将 
    Func<TResult>
    包装到一个函数中,这样我就不必再担心类型了。我只是传递了一个返回
  • null
作为参数的

表达式 lambda

,这意味着我已经使用了接受委托的第二个重载方法 
null:
Func<TResult>
另一方面,正如 Sergey 提到的,您可以将 
ReturnAsync(() => null)

分配给类型变量并传递:
null

这样,您就将 
string x = null; ‪….ReturnAsync(x);

与特定类型(本例中为字符串)链接起来,因此编译器将再次知道要使用哪个重载。
    

如何显式传递值的示例

null

1
投票

© www.soinside.com 2019 - 2024. All rights reserved.