我有一个我想测试的简单功能。功能如下:
void func()
{
// do some work
...
if(error_detected)
{
fatal_error("failure...");
exit(1);
}
}
现在我必须编写一个生成错误的测试。只有出口(1)存在失败的测试,无论如何!
这种情况通常如何处理?
我可以重写/更改功能代码,因为我可以完全控制整个项目。但是,我正在使用cppunit,并希望我可以将其作为套件中的测试之一。
更新
我想就提出的一些解决方案做一个注意事项:添加一个可以根据我们是否进行测试而实现的界面不是一种强大的测试方式看起来像。这是为什么?因为我将测试一个接口,在现实世界的测试中实现是不同的。测试结果并不能证明现实世界的情况是正确的。至少不是100%(它只证明在这种特定情况下确实采用了这条路径。)
答案 0 :(得分:4)
通常情况下,您应始终能够从客户端代码决定如何处理错误。
编辑:考虑编写解析库的场景,以及HTTP服务器项目想要使用它。虽然您的库可能具有非凡的功能,但它们将无法使用它,因为每次服务器向您的库提供无效输入时,而不是允许服务器向客户端报告HTTP 4XX(无效请求)错误,您的库不加选择地关闭整个服务器(即你的库在内部调用exit()
。)
如果可能,在您的情况下,抛出异常:
void func()
{
// do some work
...
if(error_detected)
throw std::runtime_error("failure..."); // no exit call at all
}
生产代码(这里决定是否调用退出):
try { func(); } catch(const std::runtime_error&) { exit(1); }
测试代码(此处不退出):
try {
func();
// mark test as failed here (should not be reached)
} catch(const std::runtime_error&) {
// mark test as passed here
}
如果你不能在所有情况下抛出异常(例如你的代码将从C代码中使用而不应该抛出异常),你可以将错误报告代码注入你的函数:
typedef void (*on_error)(int error_code);
void func(on_error callback)
{
// do some work
...
if(error_detected)
callback(1);
}
生产代码:
void exit_on_error(int code) { exit(code); }
func(exit_on_error);
测试代码:
enum { no_error = 0 };
int failed = no_error;
void on_error(int code) { failed = code; }
// test code:
func(on_error);
// check value of failed here
答案 1 :(得分:3)
如果你正在使用gtest,它有一整节专门用于它(见Death Tests),他们说:
任何以预期方式检查程序终止(除非通过抛出异常)的测试也是死亡测试。
如果您使用谷歌测试,那么您可以使用ASSERT_DEATH
测试死亡测试。
否则,您需要生成进程,执行测试并检查结果(生成进程的返回值)。
答案 2 :(得分:3)
如果代码窃听你的事实是它调用exit()
,那就抽象出来。
void func(IApplicationServices& app) {
// ...
app.exit();
// ...
}
然后,在测试时,传递模拟对象而不是退出应用程序的完整对象。操作系统应被视为外部系统,如此抽象,并注入依赖关系。
但抛出异常的代码将是一个更简洁的设计,因为您的处理不应该知道它是在客户端代码控制的进程中运行的。
答案 3 :(得分:2)
您可以在特定测试期间叠加exit
函数。请参阅Wrapping Linux shared library functions。