我有一个单元测试来检查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
的评论,如果您想模拟返回 null
的 Task
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/