什么是单元测试?
复杂的C/C++
代码很可能会包含错误,并且在编写代码后尝试对其进行测试类似于在大海捞针。 一种更审慎的方法是通过添加专门针对特定区域的小型(单元)测试来测试编写的各个代码段,例如,一些计算密集型C
函数或某些C++
类声称对某个数据结构进行建模,例如队列。 然后,以此理念构建的回归套件将具有单元测试的集合以及运行测试并报告结果的测试驱动程序。
为特定功能或类生成测试
对于诸如文本编辑器之类的复杂代码,外部测试人员无法生成针对特定例程的测试-测试人员对内部代码组织不会有太多想法。 在白盒测试中, Boost的使用非常方便:作为开发人员,您可以编写对类和函数进行语义检查的测试代码。 这个过程至关重要,因为您的代码的未来维护者一定会在某个时候篡改原始逻辑,并且一旦发生问题,单元测试就会失败。 通过使用白盒测试,通常无需使用调试器即可更轻松地了解问题所在。
考虑清单1中的简单字符串类。 该类不够强健,您可以使用Boost对其进行测试。
清单1.一个没有启发性的字符串类
#ifndef _MYSTRING
#define _MYSTRING
class mystring {
char* buffer;
int length;
public:
void setbuffer(char* s) { buffer = s; length = strlen(s); }
char& operator[ ] (const int index) { return buffer[index]; }
int size( ) { return length; }
};
#endif
一些典型的与字符串相关的检查将验证空字符串的长度是否为0,访问索引外导致错误消息或异常等等。 清单2显示了一些值得为任何字符串实现创建的测试。 要运行清单2中的源代码,您只需使用g ++(或任何其他符合标准的C++
编译器)对其进行编译。 请注意,不需要单独的主要功能,代码也不使用任何链接库:Boost安装中的unit_test.hpp标头包含所有必需的定义。
清单2.字符串类的单元测试
#define BOOST_TEST_MODULE stringtest
#include <boost/test/included/unit_test.hpp>
#include "./str.h"
BOOST_AUTO_TEST_SUITE (stringtest) // name of the test suite is stringtest
BOOST_AUTO_TEST_CASE (test1)
{
mystring s;
BOOST_CHECK(s.size() == 0);
}
BOOST_AUTO_TEST_CASE (test2)
{
mystring s;
s.setbuffer("hello world");
BOOST_REQUIRE_EQUAL ('h', s[0]); // basic test
}
BOOST_AUTO_TEST_SUITE_END( )
BOOST_AUTO_TEST_SUITE
和BOOST_AUTO_TEST_SUITE_END
宏分别指示测试套件的开始和结束。 各个测试位于这些宏之间,从某种意义上说,它们的语义就像C++
命名空间。 每个单独的单元测试都是使用BOOST_AUTO_TEST_CASE
宏定义的。 清单3显示了清单2中的代码输出。
清单3.清单2中的代码输出
[arpan@tintin] ./a.out
Running 2 test cases...
test.cpp(10): error in "test1": check s.size() == 0 failed
*** 1 failure detected in test suite "stringtest"
让我们详细研究一下先前清单中单元测试的创建。 基本思想是使用Boost提供的宏来测试各个类的功能。 BOOST_CHECK
和BOOST_REQUIRE_EQUAL
是Boost提供的用于验证代码输出的一些预定义宏(也称为测试工具 )。
增强测试工具
Boost具有大量的测试工具,它们基本上是用于验证表达式的宏。 测试工具的三个主要类别是BOOST_WARN
, BOOST_CHECK
和BOOST_REQUIRE
。 BOOST_CHECK
和BOOST_REQUIRE
之间的区别在于,在前一种情况下,即使断言失败,测试仍将继续,而在后一种情况下,则认为是严重错误并且测试将停止。 清单4使用一个简单的C++
代码片段来了解这些工具类别之间的区别。
清单4.使用Boost测试工具的三个变体
#define BOOST_TEST_MODULE enumtest
#include <boost/test/included/unit_test.hpp>
BOOST_AUTO_TEST_SUITE (enum-test)
BOOST_AUTO_TEST_CASE (test1)
{
typedef enum {red = 8, blue, green = 1, yellow, black } color;
color c = green;
BOOST_WARN(sizeof(green) > sizeof(char));
BOOST_CHECK(c == 2);
BOOST_REQUIRE(yellow > red);
BOOST_CHECK(black != 4);
}
BOOST_AUTO_TEST_SUITE_END( )
第一个BOOST_CHECK
失败,第一个BOOST_REQUIRE
也失败。 但是,由于BOOST_REQUIRE
失败时代码将退出,因此第二个BOOST_CHECK
尚未到达。 清单5显示了清单4代码的输出。
清单5.了解BOOST_REQUIRE和BOOST_CHECK之间的区别
[arpan@tintin] ./a.out
Running 1 test case...
e2.cpp(11): error in "test1": check c == 2 failed
e2.cpp(12): fatal error in "test1": critical check yellow > red failed
*** 2 failures detected in test suite "enumtest"
在类似的行上,如果您需要检查一些个别的函数或类