c++ - 如何在 C++ 中测试条件变量?

标签 c++ multithreading testing

我有一个非常基本的方法调用 wait()在条件变量上(来自 C++ 中的 <condition_variable>

void WaitForEvent() {
  std::unique_lock<std::mutex> lock(mutex_);
  while (!event_counter_) {
    cond_var_.wait(lock);
  } 
  return;
}

现在我想对该方法的交互进行单元测试。所以我想调用WaitForEvent , 然后调用 PostEvent它将通知条件变量并检查等待是否已停止。

void PostEvent() {
  // ...
  cond_var_.notify_all();
}

我如何在单元测试中最好地做到这一点?

到目前为止我想出的唯一解决方案是

  1. 启动一个线程调用WaitForEvent
  2. 让线程在WaitForEvent之后设置一个标志打电话
  3. 调用PostEvent在主线程中
  4. 在主线程中等待 x 秒
  5. 检查标志是否已经设置

但是,我不喜欢我不能加入这里的话题。如果我加入,那么如果 WaitForEvent,我的测试将被阻止没有按预期解锁。另外,我不喜欢在单元测试中增加延迟。

我的问题有更好的解决方案吗?提前致谢:)

编辑 1: 我的第一个解决方案如下所示

  SomeClass some_class{};
  bool has_unblocked = false;

  std::thread blocking_thread([&] {
    some_class.WaitForEvent();
    has_unblocked = true;
  });

  some_class.PostEvent();
  std::this_thread::sleep_for(std::chrono::milliseconds(10));

  REQUIRE(has_unblocked == true);

  blocking_thread.join();

最佳答案

我在我的一些单元测试中做了类似的事情,这些单元测试涉及线程和线程之间的混搭事件/消息。您提出的策略不错。

关于您的问题的一件事很突出,您的单元测试似乎只是在测试 std::condition_variable 的行为,而不是使用 cond_var 实现的代码的行为。我总是告诉我的团队要警惕编写仅测试平台和 C++ 运行时的测试——因为我们知道那是可行的。我怀疑您的测试除了 Wait and Post 代码之外还有更多内容,但这正是我想指出的。因为一旦您意识到这一点,您就可以考虑在单元测试中覆盖 Wait 和 Post 代码。

If I join,then my tests will block if WaitForEvent doesn't unblock as expected.

但在成功案例中,这无关紧要,因为您的代码可以正常工作并且测试可以快速完成。如果它确实永远阻塞,则您的单元测试发现了一个真正的错误。这是好事吧? (除了你的团队成员提示单元测试再次挂起。)

但是,如果您想避免 UT 代码中出现死锁的可能性,您可以使用 wait_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;
    }
…
}

然后是你的测试代码:

  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();

关于c++ - 如何在 C++ 中测试条件变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55626717/

相关文章:

c++ - 将 int*** 分配给 int[][][]

java - 多线程:如何让一个线程比其他线程执行得更频繁?

java - 我可以在 Junit 测试中检测到泄漏的线程吗?

java - 在java中使用线程对数组 block 进行排序

testing - 自动化站点交互

c++ - 如何计算 C++ 代码片段的 CPU 周期成本?

c# - 在 C# 中将字符串转换为字节数组以在 C++ 中将字符串写入文件

c++ - 使用数学获取范围内的数字

web-services - Web 服务测试隔离 - 但何时验证 Web 服务本身?

ruby-on-rails - 为什么实例变量有时会在 RSpec 测试中被过度使用?