如何重复调用函数直到满足模拟?
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()> *
并调用它。这很好用。
问题是:回调不一定发生在 processEvents
的 first 调用上;我所知道的是,如果我们继续在循环中调用 processEvents
,它最终会 发生。
所以我想我需要这样的东西:
while (!testing::Mock::AllExpectationsSatisfied() && !timedOut()) {
processEvents();
}
但这个虚构的 AllExpectationsSatisfied
似乎并不存在。我能找到的最接近的是 VerifyAndClearExpectations
,但如果在第一次尝试时没有达到预期(并清除它们,以启动),它会使测试立即失败。
当然,我让这个循环 运行 整整一秒左右,这将使测试通过,但也会使它不必要地变慢。
有谁知道更好的解决方案吗?
如果您正在寻找线程之间的高效同步,请查看 std::condition_variable
。在下一个事件到来之前,您使用 while
循环的实现将继续 旋转 – 用尽 CPU 资源无用。
相反,暂停代码的执行会更好,为其他线程释放处理时间,直到有事件发生,然后向暂停的线程发出信号以恢复其工作。条件变量就是这样做的。有关详细信息,请查看 the docs.
此外,您可能有兴趣研究 std::future
和 std::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 ;)
的练习
我正在编写一个带有包含事件循环的 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()> *
并调用它。这很好用。
问题是:回调不一定发生在 processEvents
的 first 调用上;我所知道的是,如果我们继续在循环中调用 processEvents
,它最终会 发生。
所以我想我需要这样的东西:
while (!testing::Mock::AllExpectationsSatisfied() && !timedOut()) {
processEvents();
}
但这个虚构的 AllExpectationsSatisfied
似乎并不存在。我能找到的最接近的是 VerifyAndClearExpectations
,但如果在第一次尝试时没有达到预期(并清除它们,以启动),它会使测试立即失败。
当然,我让这个循环 运行 整整一秒左右,这将使测试通过,但也会使它不必要地变慢。
有谁知道更好的解决方案吗?
如果您正在寻找线程之间的高效同步,请查看 std::condition_variable
。在下一个事件到来之前,您使用 while
循环的实现将继续 旋转 – 用尽 CPU 资源无用。
相反,暂停代码的执行会更好,为其他线程释放处理时间,直到有事件发生,然后向暂停的线程发出信号以恢复其工作。条件变量就是这样做的。有关详细信息,请查看 the docs.
此外,您可能有兴趣研究 std::future
和 std::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 ;)