单元测试同步代码有竞争条件?
Unit Test Synchronous Code has a Race Condition?
我已经在 git 中心上传了一些代码,可以在这里找到:
https://github.com/Shaunus87/SyncTest 包括我的原型代码和我的单元测试。
我基本上声明了我的同步代码,连接了一个事件,调用了一个最终会调用该事件的方法,并断言该事件是否被调用:
bool called = false;
var testBinsToVend = GetRoboBins();
var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue);
vendHelper.Complete += delegate () {
called = true;
};
vendHelper.DoVending();
Assert.IsTrue(called);
所有代码都是同步的(据我所知),但是如果我 运行 测试失败,如果我调试它,它通过...
我已经尝试了一些事情,似乎是 a) 我的代码是秘密异步的并且我有一个竞争条件或 b) 当 运行 决定不执行一半的代码时事件?
什么鬼?
编辑:
我也试过像下面这样设置手动重置事件:
bool called = false;
var done = new ManualResetEvent(false);
var testBinsToVend = GetRoboBins();
var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue);
vendHelper.Complete += delegate () {
called = true;
done.Set();
};
vendHelper.DoVending();
done.WaitOne();
Assert.IsTrue(called);
//was complete called?
Assert.AreEqual(true, vendHelper.Bins.All(x => x.State != VendState.Pending));
但是因为它是一行执行,所以当 done.WaitOne();
被命中时,测试永远不会到达 Assert.IsTrue(called);
行。
您的业务逻辑有问题:
private CommCommand GetLastCommand(List<CommCommand> cmds, DateTime since) {
return cmds.Where(x => x.DateTime > since)
.OrderByDescending(x => x.DateTime)
.FirstOrDefault();
}
DateTime.Now
默认只有20ms左右的分辨率。这意味着您的消息早在 DateTime > since
为真之前就已收到。当您逐步执行代码时,时间会得到调整 - Send
在原始接收之后发生的时间要长得多。
您不能依赖 DateTime.Now
进行消息排序。它根本没有足够的准确性。如果你真的认为你可以依靠发送和接收的顺序来排序(即机器在收到提示之前从不回复),请用一个简单的计数器代替它。
我已经在 git 中心上传了一些代码,可以在这里找到: https://github.com/Shaunus87/SyncTest 包括我的原型代码和我的单元测试。
我基本上声明了我的同步代码,连接了一个事件,调用了一个最终会调用该事件的方法,并断言该事件是否被调用:
bool called = false;
var testBinsToVend = GetRoboBins();
var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue);
vendHelper.Complete += delegate () {
called = true;
};
vendHelper.DoVending();
Assert.IsTrue(called);
所有代码都是同步的(据我所知),但是如果我 运行 测试失败,如果我调试它,它通过...
我已经尝试了一些事情,似乎是 a) 我的代码是秘密异步的并且我有一个竞争条件或 b) 当 运行 决定不执行一半的代码时事件?
什么鬼?
编辑: 我也试过像下面这样设置手动重置事件:
bool called = false;
var done = new ManualResetEvent(false);
var testBinsToVend = GetRoboBins();
var vendHelper = new VendingHelper(null, testBinsToVend, VendType.Issue);
vendHelper.Complete += delegate () {
called = true;
done.Set();
};
vendHelper.DoVending();
done.WaitOne();
Assert.IsTrue(called);
//was complete called?
Assert.AreEqual(true, vendHelper.Bins.All(x => x.State != VendState.Pending));
但是因为它是一行执行,所以当 done.WaitOne();
被命中时,测试永远不会到达 Assert.IsTrue(called);
行。
您的业务逻辑有问题:
private CommCommand GetLastCommand(List<CommCommand> cmds, DateTime since) {
return cmds.Where(x => x.DateTime > since)
.OrderByDescending(x => x.DateTime)
.FirstOrDefault();
}
DateTime.Now
默认只有20ms左右的分辨率。这意味着您的消息早在 DateTime > since
为真之前就已收到。当您逐步执行代码时,时间会得到调整 - Send
在原始接收之后发生的时间要长得多。
您不能依赖 DateTime.Now
进行消息排序。它根本没有足够的准确性。如果你真的认为你可以依靠发送和接收的顺序来排序(即机器在收到提示之前从不回复),请用一个简单的计数器代替它。