c# - 测试错误: The 'async' operator lacks await operator

标签 c# .net unit-testing moq

我有一个单元测试来检查null参数。测试方法是这样的:

[TestMethod]
public async Task Test_NullParam()
{
    Mock<IAuth> mockAuth = new Mock<IAuth>();
    Task<AuthenticationResult> mockResult = null;

    await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
    {
        mockAuth
          .Setup(x => x.Authenticate(null, param2, param3, param4))
          .Returns(mockResult);
    });
}

它在(async ()下显示错误。

错误是:

The async lacks await operator

mockResult 显示:

Result is always null

** 已编辑 **

类代码如下:

  public async Task<AuthenticationResult> Authenticate(string param1, string param2, string param3, string param4)
    {
        try
        {
            var authContext = new AuthenticationContext(param1);
            if (authContext.TokenCache.ReadItems().Any()) authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
            var authResult = await
            authContext.AcquireTokenAsync(param2, param3, new Uri(param4), new PlatformParameters(PromptBehavior.Auto, false));
            return authResult;
        }
        catch (Exception)
        {
            return null;
        }
    }

最佳答案

您收到错误是因为您没有在传递给 ThrowsExceptionAsync 的 lambda 中执行 await 语句。

更重要的是,您似乎是在 lambda 中执行模拟设置,而不是实际执行您正在测试的方法。您应该将模拟移到 lambda 之外,并执行您在 lambda 内测试的方法,如下所示:

[TestMethod]
public async Task Test_NullParam()
{
    // create all of your mocks that are required to run this test
    Mock<IAuth> mockAuth = new Mock<IAuth>();
    Task<AuthenticationResult> mockResult = null;
    mockAuth
        .Setup(x => x.Authenticate(null, param2, param3, param4))
        .Returns(mockResult);

    // you actually need to create the concrete type you want to test
    // you shouldn't make a unit test that just uses mocks!

    // construct the concrete type and pass in any mocks that the 
    // object requires
    var objectToTest = new MyRealObject(mockAuth.Object);

    await Assert.ThrowsExceptionAsync<ArgumentNullException>(async () =>
    {
        // actually execute the real method here, the assertion
        // is expecting this method to throw an exception, and will
        // only pass if an exception is thrown
        await objectToTest.MyMethodAsync();
    });
}

请注意,如果您正在测试的方法不是异步的,您应该将单元测试更改为非异步的,并改用 Assert.ThrowsException

编辑:

为了回应您关于模拟 Task 的评论,如果您想模拟返回 nullTask AuthenticationResult,您应该执行以下操作:

// declare the result
AuthenticationResult mockResult = null;

// set up the authenticate method to return the task
mockAuth
    .Setup(x => x.Authenticate(null, param2, param3, param4))
    .Returns(Task.FromResult(mockResult));

这里重要的部分是Task.FromResult。这将为您提供一个实际的 Task,等待时将返回 null,而不是 Task 本身为 null .

如果您想使用不为 null 的 AuthenticationResult,您将会遇到问题,因为 AuthenticationResult 类没有公共(public)构造函数,并且没有除了实际运行真正的身份验证请求之外,还有一种获取方法。 AuthenticationResult 开箱即用,不可模拟,这就是为什么 @Nkosi 提供了一篇关于 using wrapper classes to make it mockable 的文章的链接。 .

编辑2

链接的博客文章似乎并不完整,因为它没有包含所需的所有包装器类型,因此我决定自己制作它们,以便这个答案可以完整。

由于 StackOverflow 答案的字符限制限制,我不得不将文件放在 Github 上:https://github.com/DoctaJonez/DoctorJones.IdentityModel.Clients.ActiveDirectory/tree/master

添加这些类和接口(interface)后,您将能够执行以下操作:

// you can now mock authentication results, and set them up to 
// emulate whatever conditions you like
var mockResult = new Mock<IAuthenticationResultWrapper>();

// you'll need to use the IAuthenticationContextWrapper, so all the
// method signatures know about our new IAuthenticationResultWrapper
var mockAuth = new Mock<IAuthenticationContextWrapper>();

// here's how we mock the IAuthenticationContextWrapper to return our
// mocked IAuthenticationResultWrapper
mockAuth.Setup(x => x.Authenticate(null, param2, param3, param4))
        .Returns(Task.FromResult(mockResult.Object));

关于c# - 测试错误: The 'async' operator lacks await operator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48165296/

相关文章:

c# - 在 F# 中实现 C# 事件处理程序

c# 如何在客户端管理 wcf 服务代理生命周期?

c# - iTextSharp 和 PdfTable 的问题

c# - 如何在 Unity 中设置单元测试并修复缺少的程序集引用错误?

javascript - 如何使用 Ext JS 格式化方法在单元测试期间格式化日期?

c# - 使用 For 循环遍历 DataSet 中的所有 DataTable

c# - 按需输出使用 DragonFruit 的帮助

c# - 如何使用 fiddler 或任何其他工具跟踪 HttpClient 请求?

.net - .Net 使用设备相关或设备独立位图吗?

java - 如何使用默认构造函数伪造 InitialContext