给代码写测试通常是测试代码的最好方法。因为写出来的测试可以一遍又一遍地执行。当你修改了实现,你可以再次运行测试来检查一下你是否引入了任何bug。这种方法可以将你从调试中拯救出来,并引领你生产出具有更低错误倾向的代码。
作为一个一般的方针,在开发你的测试的时候,我们建议你不要把结果打印到屏幕上;而是,根据输入数据,用asserts创建一个后置条件指明期望得到哪些输出数据。
如果你在运行测试时把结果打印到了屏幕上,开始时你会去分析这些结果。然而,随着时间延长,你会越来越不注意这些打印到屏幕上的数据。即使数据指出了一个错误,你也可能不会意识到。软件测试技术
此外,如果别的人试着运行测试,他们不得不首先弄明白这些打印出来的数据是什么意思,这可能要花不少时间。反过来,如果你用了asserts,人们就只要去运行你的测试。如果发生了错误,他们会被提示在哪一行发生了错误,他们就可以去修正它。
这儿是一个测试例程的例子:
#include
#include
// 整理一个字符串的前导和追尾空白,
// 返回整理后的字符串
std::string trim_spaces( const std::string & str)
{
/* trim_spaces 的实现*/
}
void testTrimSpaces()
{
assert( trim_spaces( \" abc\") == \"abc\");
assert( trim_spaces( \"def \") == \"def\");
assert( trim_spaces( \" this is a test \") == \"this is a test\");
assert( trim_spaces( \"\") == \"\");
assert( trim_spaces( \" \") == \"\");
}
怎样建立一个测试框架,和建立它每一个步骤:
第一步:将测试代码和实际代码清楚地分隔开。要做到这一步,一个很简单的方法是把所有用来做测试的文件都放到一个特别的目录中去。每个用来做测试的文件的名字都应该以test开头,然后加上它所测试的模块/类名。例如,从testWordTokenizer.cpp文件的名字就可以看出,它是用来测试一个断词类(word tokenizer class)的。
测试用的代码仅在执行测试时才被编译。当生成实际的应用程序时,测试代码会在预处理阶段就被移除。如果我们的每个测试文件都遵循下面的模式就可以保证这一点:
// Test.cpp
#ifdef TESTING
/* testing code*/
#endif // TESTING
// End of file
于是,如果定义了TESTING,我们就是在做测试;否则,我们就是在从实际的代码生成应用程序。
第二步:所有用来测试代码片断的函数的名字都应该以Test或test开头。对于你所测试的每个模块/类,都要有一个主测试函数负责调用其他测试函数来测试模块/类的各个代码段。这样你就不需要暴露出所有函数——只要暴露出主测试函数就可以了,像下面的例子:
// TestUrlUtility –用于测试 \"Url Utility 函数族\"
#if defined( TESTING)
#include \"UrlUtility.h\"
// 这个命名空间中的函数,从这个源文件外部是不可见的
namespace // 匿名命名空间
{
void TestDivideURL()
{ /* 测试代码 */ }
void TestIsUrlValid()
{ /* 测试代码*/ }
void TestIsHttpUrlValid()
{ /* 测试代码*/ }
void TestParseHttpUrl()
{ /* 测试代码*/ }