[英]Wait for void async method to complete in unit test case
These are my business engine's methods. 这些是我的业务引擎的方法。 Upload is calling internally async method UploadAsync()
上传是在内部调用异步方法UploadAsync()
public void Upload(Stream data)
{
//Some logic
//Call private async method
UploadAsync(data);
}
private async void UploadAsync(Object data)
{
await Task.Run(() =>
{
using (var factory = new DataRepositoryFactoryObject<IAllCommandRepository>(DataRepositoryFactory))
{
factory.Repository.UploadData(data);
}
}
);
}
This is unit test case for Upload() method 这是Upload()方法的单元测试用例
[TestMethod, TestCategory("Unit")]
public void Upload_ValidData_Success()
{
//other logic to setup mock repository
//call public method which calls async method
engine.Upload(data);
_mockAllCommandRepository.Verify(x => x.Upload(It.Is<Object>(t => t != null)), Times.Once);
}
This test case is getting failed occasioally at verify method with following exception: 此测试用例在验证方法偶尔失败,但有以下异常:
016-10-06T19:25:20.4982657Z ##[error]Expected invocation on the mock once, but was 0 times: x => x.Upload(It.Is<Object>(t => t != null)), Times.Once);
As per my analysis verify method gets called before calling async method. 根据我的分析,在调用异步方法之前调用验证方法。 This can be reason of failure of this test case.
这可能是此测试用例失败的原因。 How can I verify that a method was called on a mock when the method itself is called in a delegate passed to Task.Run?
当在传递给Task.Run的委托中调用方法本身时,如何验证在模拟上调用方法? By time mock.Verify is called the Task still hasn't executed.
按时间mock.Verify被称为任务仍然没有执行。 Could anyone please provide some solution so that this test case will pass each and every time
任何人都可以提供一些解决方案,以便这个测试用例每次都会通过
As others have noted, the best solution is to make the method return Task
. 正如其他人所说, 最好的解决方案是让方法返回
Task
。 Task
-returning async
methods are more easily testable: Task
返回async
方法更容易测试:
private async Task UploadAsync(Object data)
{
await Task.Run(() =>
{
using (var factory = new DataRepositoryFactoryObject<IAllCommandRepository>(DataRepositoryFactory))
{
factory.Repository.UploadData(data);
}
});
}
private async void Upload(Object data)
{
await UploadAsync(data);
}
Then your unit test can be: 然后你的单元测试可以是:
[TestMethod, TestCategory("Unit")]
public async Task Upload_ValidData_Success()
{
//other logic to setup mock repository
//call public method which calls async method
await engine.UploadAsync(data);
_mockAllCommandRepository.Verify(x => x.Upload(It.Is<Object>(t => t != null)), Times.Once);
}
However, if for some reason you do need to test an async void
method, it's possible to do by using my AsyncContext
type : 但是,如果由于某种原因您需要测试
async void
方法,则可以使用我的AsyncContext
类型 :
[TestMethod, TestCategory("Unit")]
public void Upload_ValidData_Success()
{
//other logic to setup mock repository
//call public method which calls async method
AsyncContext.Run(() => engine.Upload(data));
_mockAllCommandRepository.Verify(x => x.Upload(It.Is<Object>(t => t != null)), Times.Once);
}
Side note: In an ideal scenario, I'd recommend adding an UploadDataAsync
to your repository, and then remove the Task.Run
. 附注:在理想情况下,我建议将
UploadDataAsync
添加到存储库,然后删除Task.Run
。
One of the main benefits of unit tests is that they help you design better code. 单元测试的主要好处之一是它们可以帮助您设计更好的代码。 Most of the time, when you are struggling to write a test, it is telling you that your code needs to be improved, not your test.
大多数情况下,当您努力编写测试时,它告诉您需要改进代码,而不是测试。
In this case the issue is using a void
return type with an async
method, something which Stephen Cleary advises against . 在这种情况下,问题是使用带有
async
方法的void
返回类型,这是Stephen Cleary 建议的 。 Indeed, one of the reasons he cites in his article is: 实际上,他在文章中引用的原因之一是:
Async void methods are difficult to test.
异步void方法很难测试。
I think one of his most convincing arguments against async void
methods is this: 我认为他对
async void
方法的一个最有说服力的论点是这样的:
When the return type is Task, the caller knows it's dealing with a future operation;
当返回类型为Task时,调用者知道它正在处理将来的操作; when the return type is void, the caller might assume the method is complete by the time it returns.
当返回类型为void时,调用者可能会认为该方法在返回时已完成。
In case you're not convinced yet, here's another article which contains a couple of other reasons to avoid async void
. 如果您还不相信, 这里有另一篇文章 ,其中包含避免
async void
的其他几个原因。
In summary, you should change your method to return a Task
. 总之,您应该更改方法以返回
Task
。 Then you will be able to wait on it in the test. 然后你就可以在测试中等待它了。
private async Task UploadAsync(Object data)
{
return Task.Run(() => {
using (var factory = new DataRepositoryFactoryObject<IAllCommandRepository>(DataRepositoryFactory))
{
factory.Repository.UploadData(data);
}
});
}
and the test... 和测试......
[TestMethod, TestCategory("Unit")]
public void Upload_ValidData_Success()
{
//other logic to setup mock repository
//call public method which calls async method
engine.Upload(data).Wait();
_mockAllCommandRepository.Verify(x => x.Upload(It.Is<Object>(t => t != null)), Times.Once);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.