如何重复调用函数直到满足模拟?

How to call a function repeatedly until a mock has been satisfied?

我正在编写一个带有包含事件循环的 C(不是 C++)接口的库,称之为 processEvents。这应该在循环中调用,并在发生某些事情时调用用户定义的回调。本例中的 "something" 由在不同线程中接收的 RPC 响应触发,并添加到主线程上由 processEvents 使用的事件队列中。

所以从我图书馆的用户的角度来看,用法是这样的:

function myCallback(void *userData) {
  // ...
}

int main() {
  setCallback(&myCallback, NULL);
  requestCallback();
  while (true) {
    processEvents(); /* Eventually calls myCallback, but not immediately. */
    doSomeOtherStuff();
  }
}

现在我想使用 Google 测试和 Google 模拟来测试回调是否确实被调用了。

我已经使用 MockFunction<void()> 来拦截实际的回调;这是由 C 风格的静态函数调用的,该函数将 void *userData 转换为 MockFunction<void()> * 并调用它。这很好用。

问题是:回调不一定发生在 processEventsfirst 调用上;我所知道的是,如果我们继续在循环中调用 processEvents,它最终会 发生。

所以我想我需要这样的东西:

while (!testing::Mock::AllExpectationsSatisfied() && !timedOut()) {
  processEvents();
}

但这个虚构的 AllExpectationsSatisfied 似乎并不存在。我能找到的最接近的是 VerifyAndClearExpectations,但如果在第一次尝试时没有达到预期(并清除它们,以启动),它会使测试立即失败。

当然,我让这个循环 运行 整整一秒左右,这将使测试通过,但也会使它不必要地变慢。

有谁知道更好的解决方案吗?

如果您正在寻找线程之间的高效同步,请查看 std::condition_variable。在下一个事件到来之前,您使用 while 循环的实现将继续 旋转 – 用尽 CPU 资源无用。

相反,暂停代码的执行会更好,为其他线程释放处理时间,直到有事件发生,然后向暂停的线程发出信号以恢复其工作。条件变量就是这样做的。有关详细信息,请查看 the docs.

此外,您可能有兴趣研究 std::futurestd::promise,它们基本上封装了等待异步发生的模式。查找更多详细信息 here

发布问题后,我想到了使用每次模拟函数调用都会递减的计数器。但是@PetrMánek 的回答给了我一个更好的主意。我最终做了这样的事情:

MockFunction<void()> myMockFunction;

// Machinery to wire callback to invoke myMockFunction...

Semaphore semaphore; // Implementation from 
EXPECT_CALL(myMockFunction, Call())
    .WillRepeatedly(Invoke(&semaphore, &Semaphore::notify));
do {
  processEvents();
} while (semaphore.try_wait());

(我使用的是信号量而不是 std::condition_variable,因为 (1) 虚假唤醒和 (2) 它可以在我期望多次回调调用的情况下使用。)

当然,这仍然需要一个整体超时,这样失败的测试就不会永远挂起。还可以向 try_wait() 添加一个可选的超时,以提高 CPU 的效率。这些改进留作 reader ;)

的练习