【发布时间】:2018-08-01 11:18:13
【问题描述】:
在我的 WPF MVVM 中,我有两个 单独运行时工作 单元测试,它们测试两个按钮命令方法:
[TestMethod]
public async Task TestMethod1()
{
// Arrange
var interfaceStub = new StubInterface();
interfaceStub.Method = () => "Message";
var viewModel = new ViewModel(interfaceStub);
// Act
await Task.Run(() => viewModel.GenerateCommand.Execute());
// Assert
Assert.AreEqual("Message", viewModel.Response);
}
[TestMethod]
public async Task TestMethod2()
{
// Arrange
var interfaceStub = new StubInterface();
interfaceStub.Method = () => "Message";
var viewModel = new ViewModel(interfaceStub);
// Act
await Task.Run(() => viewModel.VerifyCommand.Execute());
// Assert
Assert.AreEqual("Message", viewModel.Response);
}
VerifyCommand 和GenerateCommand 实际上是实现ICommand 的AsyncRelayCommand 类型,因此它们是async void,我必须在测试中使用Task.Run() 在单独的线程上运行它们。 Method1 和Method2 实际上分别代表按钮使用的ExecuteMethod1CommandAsync 和ExecuteMethod2CommandAsync 命令。
问题是,如果我分别运行这些测试,它们都会通过。 但是,一旦我尝试同时测试它们两个,Assert.AreEqual() 失败:
预期: ,实际
这显然是因为其中一个测试没有等待线程完成,并且在断言步骤还没有返回值。我将System.Threading.Thread.Sleep(5000); 添加到两个测试方法中,然后当我再次一起运行它们时,两个测试都通过了(这进一步证明了这一点)。
为什么单独运行它们会使测试方法等待,但单独运行它们会使其中一个不等待?
编辑:当我单独运行它们时,所花费的时间:~140 毫秒。当我一起运行它们时:通过的又是〜140 ms,另一个不通过的只有90 ms(证明我的发现)
编辑2:执行方法:
// Executes the action
public async void Execute(object parameter)
{
// Do something
try
{
await execute(parameter);
}
finally
{
// Do something
}
}
execute 是Func<object, Task>。这显然是问题发生的地方——当执行(参数)启动时,它会立即返回到TestMethod 中的任务。解决这个问题的最佳方法是什么?
【问题讨论】:
-
在测试资源管理器中的 Visual Studio 上,您可以在搜索旁边输入一个带有“并行运行测试”的按钮。删除
async修饰符,试试这个方法并行运行单元测试。 -
@Sidron 我无法删除异步...我必须
await才能完成任务。并行运行没有帮助。 -
@Damien_The_Unbeliever 是的,这正是发生的事情,几分钟前我才意识到这一点,因为我在 async void 中的 await 前后运行了一个无限循环..
-
几乎在所有情况下,
await Task.Run()都是毫无意义的。您要求 TPL 找到 其他线程 来运行一些代码,然后宣布(使用await)-“好吧,对于 this 线程没有任何用处做,直到其他工作完成”。去掉中间人 - 使用 your 线程来运行该代码。 -
是的,我通常会做的例外是 - 如果您有一个 CPU 绑定操作,您需要在不需要访问 UI 对象的地方执行,并且您当前在 UI 上下文中执行,that 是适合
await Task.Run()的时间。 (或其他单线程上下文)。但根据我的大部分经验,人们在使用它时没有考虑它是否合适。
标签: c# .net unit-testing microsoft-fakes