Sri*_*lan 37 c# nunit async-await
我有一个控制器UserController有这个动作
// GET /blah
public Task<User> Get(string domainUserName)
{
if (string.IsNullOrEmpty(domainUserName))
{
throw new ArgumentException("No username specified.");
}
return Task.Factory.StartNew(
() =>
{
var user = userRepository.GetByUserName(domainUserName);
if (user != null)
{
return user;
}
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, string.Format("{0} - username does not exist", domainUserName)));
});
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试为我抛出404异常的情况编写一个测试.
这是我尝试过的输出 -
1)
[Test]
public void someTest()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
Assert.That(async () => await userController.Get("foo"), Throws.InstanceOf<HttpResponseException>());
}
Run Code Online (Sandbox Code Playgroud)
结果 测试失败
Expected: instance of <System.Web.Http.HttpResponseException>
But was: no exception thrown
Run Code Online (Sandbox Code Playgroud)
2)
[Test]
public void someTest()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var httpResponseException = Assert.Throws<HttpResponseException>(() => userController.Get("foo").Wait());
Assert.That(httpResponseException.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
Run Code Online (Sandbox Code Playgroud)
结果 测试失败
Expected: <System.Web.Http.HttpResponseException>
But was: <System.AggregateException> (One or more errors occurred.)
Run Code Online (Sandbox Code Playgroud)
3)
[Test]
public void someTest()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var httpResponseException = Assert.Throws<HttpResponseException>(async () => await userController.Get("foo"));
Assert.That(httpResponseException.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
Run Code Online (Sandbox Code Playgroud)
结果 测试失败
Expected: <System.Web.Http.HttpResponseException>
But was: null
Run Code Online (Sandbox Code Playgroud)
4)
[Test]
[ExpectedException(typeof(HttpResponseException))]
public async void ShouldThrow404WhenNotFound()
{ var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var task = await userController.Get("foo");
}
Run Code Online (Sandbox Code Playgroud)
结果 测试通过
问题 -
对这些行为及其原因的任何比较都会很棒!
Ste*_*ary 48
你看到的问题是由于async void.
特别是:
1)async () => await userController.Get("foo")被转换为TestDelegate,返回void,所以你的lambda表达式被视为async void.因此测试运行器将开始执行lambda但不等待它完成.lambda在Get完成之前返回(因为它是async),并且测试运行器看到它返回时没有异常.
2)Wait包装任何例外AggregateException.
3)同样,asynclambda被视为async void,因此测试运行器不等待其完成.
4)我建议你做这个,async Task而不是async void,但在这种情况下,测试运行器确实等待完成,从而看到异常.
根据这个错误报告,在下一个NUnit版本中有一个修复.在此期间,您可以构建自己的ThrowsAsync方法; xUnit的一个例子就在这里.
Jam*_*oss 31
我不确定它何时被添加,但当前版本的Nunit(编写时为3.4.1)包含ThrowsAsync方法
请参阅https://github.com/nunit/docs/wiki/Assert.ThrowsAsync
例:
[Test]
public void ShouldThrow404WhenNotFound()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var exception = Assert.ThrowsAsync<HttpResponseException>(() => userController.Get("foo"));
Assert.That(exception.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
Run Code Online (Sandbox Code Playgroud)
Sri*_*lan 11
这篇博客讨论了与我类似的问题.
我按照那里提出的建议,进行了这样的测试 -
[Test]
public void ShouldThrow404WhenNotFound()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
var aggregateException = Assert.Throws<AggregateException>(() => userController.Get("foo").Wait());
var httpResponseException = aggregateException.InnerExceptions
.FirstOrDefault(x => x.GetType() == typeof(HttpResponseException)) as HttpResponseException;
Assert.That(httpResponseException, Is.Not.Null);
Assert.That(httpResponseException.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
}
Run Code Online (Sandbox Code Playgroud)
我对它不太满意,但这很有效.
编辑1
在@StephenCleary的启发下,我添加了一个静态助手类来完成我正在寻找的断言.它看起来像这样 -
public static class AssertEx
{
public static async Task ThrowsAsync<TException>(Func<Task> func) where TException : class
{
await ThrowsAsync<TException>(func, exception => { });
}
public static async Task ThrowsAsync<TException>(Func<Task> func, Action<TException> action) where TException : class
{
var exception = default(TException);
var expected = typeof(TException);
Type actual = null;
try
{
await func();
}
catch (Exception e)
{
exception = e as TException;
actual = e.GetType();
}
Assert.AreEqual(expected, actual);
action(exception);
}
}
Run Code Online (Sandbox Code Playgroud)
我现在可以进行类似的测试 -
[Test]
public async void ShouldThrow404WhenNotFound()
{
var mockUserRepository = new Mock<IUserRepository>();
mockUserRepository.Setup(x => x.GetByUserName(It.IsAny<string>())).Returns(default(User));
var userController = new UserController(mockUserRepository.Object) { Request = new HttpRequestMessage() };
Action<HttpResponseException> asserts = exception => Assert.That(exception.Response.StatusCode, Is.EqualTo(HttpStatusCode.NotFound));
await AssertEx.ThrowsAsync(() => userController.Get("foo"), asserts);
}
Run Code Online (Sandbox Code Playgroud)
这是文档中的示例:
var ex = Assert.ThrowsAsync<ArgumentException>(async () => await MethodThatThrows());
Run Code Online (Sandbox Code Playgroud)
ThrowsAsyncasync/await| 归档时间: |
|
| 查看次数: |
21099 次 |
| 最近记录: |