这是我尝试测试比赛条件的代码, 我有遗留代码,我可以在一定程度上改变。 在我的main函数中,我有一个函数,它返回一个我们等待的Task和另一个不能被阻止的函数,因为它在不同的线程上运行。
在原始代码中,我们不关心结果,我们只是初始化一些类,我测试ViewModel不是null。
在我给出的示例代码中,我更改了代码以举例说明竞争条件的问题。 目前,我的测试将失败。 如何正确测试我的比赛条件?
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
Myclass tempClass = new Myclass();
tempClass.CreateImage();
Assert.AreEqual(3, tempClass.Sum);
}
}
public class Myclass
{
public int Sum;
public Myclass()
{
Sum = 0;
}
public async Task CreateImage()
{
await InternalFunction();
await Task.Run(() => Physics());
}
public async Task InternalFunction()
{
await Task.Run(() =>
{
Math();
});
}
public void Math()
{
Sum += 1;
}
public void Physics()
{
Sum += 2;
}
}
如果我运行测试,sum属性将为1,而不是预期的3。如何更改代码以便能够执行CreateImage()
函数的所有流程,并且只有在完成所有线程后,我想断言TempClass的结果/内容。
答案 0 :(得分:2)
CreateImage
方法是异步的,但是您的单元测试方法不是,因此您的测试可能会在CreateImage完成之前完成。
您没有指定您正在使用的NUnit版本,但以下版本适用于最新版本的NUnit 3
[TestFixture]
public class UnitTest1
{
[Test]
public async Task TestMethod1()
{
Myclass tempClass = new Myclass();
await tempClass.CreateImage();
Assert.AreEqual(3, tempClass.Sum);
}
}
当然,这假设MyClass
是线程安全的 - 如果您的实际代码使用多个线程同时修改MyClass
实例的状态,那么您可能还需要考虑使用同步机制比如BCL内置的其中一个 - https://docs.microsoft.com/en-us/dotnet/standard/threading/synchronizing-data-for-multithreading
另外,您可以考虑使用Stephen Cleary开发的一些异步友好助手 - https://github.com/StephenCleary/AsyncEx
答案 1 :(得分:2)
您还必须等待测试中的代码,否则Aseert将在代码完成之前进行:
[TestMethod]
public async Task TestMethod1()
{
Myclass tempClass = new Myclass();
await tempClass.CreateImage();
Assert.AreEqual(3, tempClass.Sum);
}
但对我来说,这段代码有一些pifalls。 Task.Run
中有很多包装同步代码,它现在不会带来任何好处。此外Sum
不是线程安全的,所以如果在任何时间线程它将被线程访问,则会发生并发的坏事。