如何在C+中测试条件变量+;? 我有一个非常好的基本方法,它调用了一个条件变量(< C++ > > >条件>变量>代码> void WaitForEvent(){ std::唯一锁(互斥锁); 而(!事件计数器){ 条件变量等待(锁定); } 返回; }
现在我想对该方法的交互进行单元测试。因此我想调用如何在C+中测试条件变量+;? 我有一个非常好的基本方法,它调用了一个条件变量(< C++ > > >条件>变量>代码> void WaitForEvent(){ std::唯一锁(互斥锁); 而(!事件计数器){ 条件变量等待(锁定); } 返回; },c++,multithreading,testing,C++,Multithreading,Testing,现在我想对该方法的交互进行单元测试。因此我想调用WaitForEvent,然后调用PostEvent,它将通知条件变量并检查等待是否已停止 void PostEvent(){ // ... 条件变量通知所有(); } 我如何在单元测试中最好地做到这一点 到目前为止,我提出的唯一解决办法是 启动一个调用WaitForEvent 使线程在调用WaitForEvent后设置一个标志 在主线程中调用PostEvent 在主线程中等待x秒 检查是否已设置该标志 但是,我不喜欢不能在这里加入线程的事实。如
WaitForEvent
,然后调用PostEvent
,它将通知条件变量并检查等待是否已停止
void PostEvent(){
// ...
条件变量通知所有();
}
我如何在单元测试中最好地做到这一点
到目前为止,我提出的唯一解决办法是
WaitForEvent
WaitForEvent
后设置一个标志PostEvent
WaitForEvent
没有按预期解除阻止,我的测试将被阻止。此外,我不喜欢在单元测试中添加延迟
有没有更好的办法解决我的问题?提前谢谢:)
编辑1:我的第一个解决方案如下所示
SomeClass-someu-class{};
bool has_unblocked=false;
std::线程阻塞_线程([&]{
一些类。WaitForEvent();
has_unblocked=true;
});
某个类的PostEvent();
std::this_线程::sleep_for(std::chrono::毫秒(10));
REQUIRE(has_unblocked==true);
阻塞线程。连接();
我在我的一些单元测试中做了类似的事情,这些测试涉及线程和线程之间的mashalling事件/消息。你提出的策略不错
一个问题,你的单元测试只是简单地测试了
wait\u for
代替wait
。其中,产品代码可能不依赖于超时,但UT依赖于
class SomeClass
{
bool _running_as_unittest;
void WaitForEvent() {
std::unique_lock<std::mutex> lock(mutex_);
while (!event_counter_) {
if (_running_as_unittest) {
cond_var.wait(lock, FiveSeconds); // give the test a chance to escape
if (!event_counter) {
_errorCondition = true;
}
}
else {
cond_var.wait(lock); // wait forever
}
}
return;
}
…
}
class-SomeClass
{
作为单元测试运行的布尔;
void WaitForEvent(){
std::唯一锁(互斥锁);
而(!事件计数器){
如果(作为单元测试运行){
cond_var.wait(lock,五秒钟);//给测试一个逃脱的机会
如果(!事件计数器){
_errorCondition=true;
}
}
否则{
cond_var.wait(lock);//永远等待
}
}
返回;
}
…
}
然后您的测试代码:
SomeClass some_class{};
bool has_unblocked = false;
some_class._running_as_unittest = true;
some_class._errorCondition = false;
std::thread blocking_thread([&] {
some_class.WaitForEvent();
has_unblocked = true;
});
some_class.PostEvent();
for (int x = 0; (x < 500) && !has_unblocked; x++) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
REQUIRE(has_unblocked == true);
REQUIRE(someclass._errorCondition == false);
// todo - if has_unblocked is false, you could consider invoking `blocking_thread.native_handle` and then invoking `pthread_kill` or `TerminateThread` as appropriate. instead of invoking `join`.
blocking_thread.join();
SomeClass-someu-class{};
bool has_unblocked=false;
某些类。运行作为单元测试的类=true;
某些类。\u errorCondition=false;
std::线程阻塞_线程([&]{
一些类。WaitForEvent();
has_unblocked=true;
});
某个类的PostEvent();
对于(int x=0;(x<500)&&!已解锁;x++){
std::this_线程::sleep_for(std::chrono::毫秒(10));
}
REQUIRE(has_unblocked==true);
REQUIRE(someclass.\u errorCondition==false);
//todo-HasununBuffice为false时,可以考虑调用“BuffjixTrime.nTyVeWaRead”,然后适当调用“pthRead Type”或“TealthType”。而不是调用“join”。
阻塞线程。连接();
在这种情况下,我通常使用std::async
返回一个std::future
,并且我还指定操作超时,以避免在CI中卡住的测试
#include <future>
#include <condition_variable>
#include <chrono>
#include <mutex>
class MySystem {
public:
MySystem() = default;
std::future<bool> WaitForEvent(std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> l(cv_m_);
return std::async(std::launch::async,
// for this lambda you need C++14
[this, timeout, lock{std::move(l)}] () mutable {
if (cv_.wait_for(lock, timeout) == std::cv_status::timeout) {
return false;
}
return true;
});
}
void PostEvent() {
std::lock_guard<std::mutex> guard(cv_m_);
cv_.notify_all();
}
private:
std::condition_variable cv_;
std::mutex cv_m_;
};
TEST(xxx, yyy) {
MySystem sut;
auto result = sut.waitForEvent(std::chrono::seconds(1));
ASSERT_FALSE(result.get());
result = sut.waitForEvent(std::chrono::seconds(1));
sut.PostEvent();
ASSERT_TRUE(result.get());
}
#包括
#包括
#包括
#包括
类MySystem{
公众:
MySystem()=默认值;
std::future WaitForEvent(std::chrono::毫秒超时){
std::唯一锁定l(cv_m_);
返回std::async(std::launch::async,
//对于这个lambda,您需要C++14
[this,timeout,lock{std::move(l)}]()可变{
如果(cv_u.wait_ufor(锁定,超时)=标准::cv_u状态::超时){
返回false;
}
返回true;
});
}
void PostEvent(){
标准:锁紧防护装置(cv_m_);
cv_uu.notify_uall();
}
私人:
std::条件变量cv;
std::互斥cv_m_;
};
测试(xxx,yyy){
MySystem-sut;
自动结果=sut.waitForEvent(std::chrono::seconds(1));
ASSERT_FALSE(result.get());
结果=sut.waitForEvent(标准:计时:秒(1));
sut.PostEvent();
ASSERT_TRUE(result.get());
}
std::future
节省了我手动创建和连接线程的工作量,并允许我以一种良好的方式检查操作结果(例如超时时的false
)。在调用std::mutex
之前锁定std::async
可以保证在执行notify\u all
之前,您的条件变量将开始等待,非常感谢-这回答了我的所有问题:)另外,我的测试实际上测试了更多的行为——我只是想在这里展示相关部分,以免混淆任何读者:我不喜欢为SomeClass
(比如runnin)编写额外接口的想法