编写检查定时行为的快速测试
Writing fast tests that check timed behavior
我有下面的类(当然,为示例简化了):
class file_handler_c {
public:
err_t init(int msecs);
err_t write(byte* buffer);
}
这个类要求init
在任何write
之前被调用,然后你可以使用这个类来write
到一个文件。但是,在msecs
毫秒之后,write
停止写入文件并返回一个错误。
我的问题是——如何为这种行为创建一个快速单元测试?任何足够小的值都会创建一个不确定的测试,有时会因为机器上运行的其他进程而失败。但是,我希望测试尽可能快,不包括任何sleep
或类似的。我正在使用谷歌测试和谷歌模拟。
首先,我必须稍微转移一下你的实际问题。请不要创建这样的接口。无论何时创建对象,在其生命周期结束之前,它的所有函数都必须是可调用的。非正式的生命周期约束,如"init()必须在write()之前调用",或者更糟糕的是"总是在析构函数之前调用close()",编译器无法检查,因此容易出错。
因此,我不认为你应该在测试中解决这个问题,而应该在测试代码的设计中解决。无论何时编写测试很难,可以肯定的是,您的接口存在缺陷。
我的建议是把计时和写作分开。创建一个定时器类,例如:
#include <memory>
#include <chrono>
template<typename T>
class Timer {
private:
std::chrono::milliseconds time_to_live;
std::shared_ptr<T> timed_object;
public:
template<typename... Arg>
Timer(std::chrono::milliseconds ttl, Arg... args):
time_to_live{ttl},
timed_object{std::make_shared<T>(args...)} {};
std::weak_ptr<T> get() { return {timed_object}; };
// ...
// when the defined time is over, timed_object will be set to nullptr somehow.
};
像这样使用:
#include <chrono>
#include <iostream>
#include <fstream>
int main(int, char**)
{
using namespace std::literals::chrono_literals;
auto timed_ostream = Timer<std::ofstream>{42ms, "filename"};
if( !timed_ostream.get().expired() ) {
// os is a shared_ptr. That guarantees, that the ostream will not
// be closed while you are still writing.
auto os = timed_ostream.get().lock();
(*os) << "whatever";
} // now os will be destroyed. The ofstream might be destroyed
// as well now, when the 42ms are over.
} // OK, here we destroy the timer and therefore the ofstream,
// if it is still alive.
有了这个接口,你可以很容易地编写一个简单的测试用例,而不是ostream,例如int:
#include <chrono>
#include <cassert>
using namespace std::literals::chrono_literals;
void test_timed_object_valid_after_init()
{
auto clock = std::chrono::high_resolution_clock{};
auto start = clock.now();
auto timed_int = Timer<int>{2000ms,42}; // valid for 2000ms
assert(timed_int.get().expired()); // should still be here
} // The timer will be destroyed here. That destroys the shared_ptr
// and the object as well. The long lifetime does not matter.
void test_timed_object_invalid_after_time()
{
auto clock = std::chrono::high_resolution_clock{};
auto start = clock.now();
auto timed_int = Timer<int>{1ms,42}; // valid for 1ms
// you did not want sleep(), so we do busy waiting.
// Prefer usleep() instead.
// busy wait 1ms as exactly as possible.
while( clock.now() - start < 1ms ) {}
assert(timed_int.get().expired()); // should be gone now.
}
注意,这里每个测试用例只检查一个场景。不要尝试在一个测试用例中测试这两个需求。那么,你要么必须使用较长的生命周期来检查对象在初始化后是否安全存在,要么选择较短的生命周期来检查对象在初始化后是否消失。
注意:这篇文章中的所有代码都应该可以编译,但当然可能在某些地方仍然存在错误。这些留给学生作为练习;-)
相关文章:
- 使用 gtest 框架在单元测试代码中检查目标对象的私有变量的最佳实践是什么?
- 如何在多个 Catch2 测试用例中检查相同的条件
- 如何使用谷歌测试检查两个枚举类元素的相等性?
- 助推.测试检查结构是否相等
- 如何检查函数是在C++单元测试中的析构函数中调用的
- 如何使用 cmake 在C++中快速检查(基于属性的测试)工作?
- C++回文检查解决方案被一个测试用例跳闸
- 无法在谷歌测试中检查异常类型
- 单元测试:检查是否不应编译某些表达式
- 支架检查功能仅测试输入的前 2 个
- 我如何检查一次测试中有多少个``期望_*`呼叫失败
- 交叉围栏GCC:在检查动态链接器特征时,在GCC_NO_EXECUTABLES之后不允许链接测试
- Google单元测试以检查表打印
- 检查两个数组中的相似元素,为某些测试返回正确的值,为其他测试返回不正确的值
- 如何使用谷歌测试零或一个函数调用进行检查
- Windows 上的 Google 测试框架检查您是否以交互方式运行
- 如何在还原提交并保留单元测试时检查测试
- 使用 GTEST 1.6 进行单元测试:如何检查打印的内容
- 测试检查该方法返回一个数字范围
- c++单元测试检查输出是否正确