软件测试实验学习笔记系列4--CppUnit

CppUnit单元测试工具

CppUnit也是对xUnit家族中的一个成员,C++语言实现的一个单元测试的框架,Micheal FeathersJUnit移植过来了,GNULGPL条约。

CppUnit按照层次来管理测试,最底层的就是TestCase,当有了几个TestCase以后,可以将它们组织成TestFixture。在TestFixture,可以建立被测试的类的实例,并编写TestCase对类实例进行测试,多个TestFixture可以通过TestSuite来对测试进行管理。

通过派生TestFixture类来设计某个类或某组相关功能的单元测试,Fixture定义公共函数setUp()初始化每个成员变量,tearDown()来释放setUp中使用的资源。在每个测试中,CPPUNIT_ASSERT(bool)来判断某个函数和表达式的正确性,在派生类的声明中,通过CPPUNIT_TEST来增加对应的测试函数,通过CPPUNIT_TEST_SUITECPPUNIT_TEST_SUITE_END来分装所有的测试函数,规定这些测试函数执行的顺序.

1 CppUnit单元测试环境的建立

1.1 在Linux下安装

方法1

在使用Ubuntu软件库中编译好的了的库文集和文档,一条命令解决问题:

         sudo apt-get install libcppunit-dev libcppunit-doc 参考[1]

参考[2]介绍了一个有意思的东西,build-essential(包括libc6.so,libc6-dev.so,gcc以及make等工具),如果没有这个基本包的话,使用源代码安装编译时,./configure部分就会报错。

方法2-使用源代码编译

CppUnit的官方网站:http://sourceforge.net/projects/cppunit/files/cppunit/

源代码可以在官方网站上下载上下载,最新CppUnit的版本是1.12.1(从官方网站上来看,这个版本是2008年2月20更新的,5年过去了都没有更新,所以我做了一个CppUnit1.12.1的源码包网盘的公开链接:

 http://pan.baidu.com/share/link?shareid=1903199222&uk=556148328

tar-xzf cppunit-1.12.1.tar.gz

cd cppunit-1.12.1

./configure

make

make check

sudo make install

       本来没有什么好说的,关键是出了点问,在使用make时报错了。错误如下:

/bin/bash ../../libtool --tag=CXX   --mode=link g++  -g -O2 -ldl  -o DllPlugInTester DllPlugInTester.o CommandLineParser.o ../../src/cppunit/libcppunit.la -lm
mkdir .libs
g++ -g -O2 -o .libs/DllPlugInTester DllPlugInTester.o CommandLineParser.o  -ldl ../../src/cppunit/.libs/libcppunit.so -lm 
../../src/cppunit/.libs/libcppunit.so: undefined reference to `dlsym'
../../src/cppunit/.libs/libcppunit.so: undefined reference to `dlopen'
../../src/cppunit/.libs/libcppunit.so: undefined reference to `dlclose'
collect2: error: ld returned 1 exit status
make[2]: *** [DllPlugInTester] Error 1
make[2]: Leaving directory `/home/xc-pc/software/cppunit-1.12.1/src/DllPlugInTester'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/xc-pc/software/cppunit-1.12.1/src'

make: *** [all-recursive] Error 1
也不知道是因为自己的自己的所安装的CppUnit的版本的问题还是其他的问题。(看起来这个错误够吓人,对比到CppUnit的Makefile文件有800多行,就会觉得出个错误没什么)

解决方案:

     从上面的出现的错误可以看出,是cppunit-1.12.1/src/DllPlugInTester目录下编译发生了错误,也就是说是那个目录下的Makefile出了问题,cd 到cppunit-1.12.1/src/DllPlugInTester目录,使用vi(或者其他的编辑器,如emacs,gedit)打开Makefile.找到LIBS= -lm,将LIBS= -lm  改为LIBS= -lm -ldl 

    需要进行相应的修改的还有cppunit-1.12.1/examples/simple目录下的Makefile文件.

至此,再重新make一下,可以看到没有报错了。然后就可以继续下去了。如果嫌源代码安装的方式太过于繁琐,尤其是出了问题之后。

1.2 在VC 6.0/window下安装(参考6)

a) 从官方网站上下载CppUnit的tar包并解压到本地磁盘,比如D:\CppUnit1.12.1

b) 编译、安装CppUnit库。在VC中打开D:\CppUnit1.12.1\src\CppUnitLibraries.dsw,选择“Build | BatchBuild...”,选中所有的项目,点击build按钮。在D:\CppUnit1.12.1\lib\下生成所需要的所有库文件。

c)在Visual C++中进行设置。告诉VC在哪里能找到CppUnit中的程序文件和库文件:打开“Tools | Options...”,切换到'Directories'标签页,选择'include files',添加D:\CppUnit1.12.1\include\;切换到'libraries files'标签页,添加CPPUNITHOME/lib/;切换到'source files'标签页,添加D:\CppUnit1.12.1\src\cppunit\,保存。

d) 在测试代码中进行设置。在VC中打开你写的测试程序,启动Project Settings对话框,切换到'C++'标签页,选择'Code generation'项,对于release版,选择'Multithreaded DLL',对于Debug版,选择'Debug Multithreaded DLL'。同样是在这个标签页,选择'C++ langage'项,选择All Configurations,选择'enable Run-Time Type Information (RTTI)'。切换到'Link'标签页,在'Object/library modules'中添入需要的lib文件cppunitX.lib (debug模式为cppunitd.lib, release 模式为cppunit.lib )和testrunnerX.lib(debug模式为testrunnerd.lib, release 模式testrunner.lib,debug Unicode模式为testrunnerud.lib, release Unicode模式为testrunneru.lib)

e).添加系统路径。为使测试程序在运行时能找到CppUnit提供的dll,我们在环境变量中指出CppUnit提供的dll的路径:在我的电脑中,打开环境变量,编辑系统变量中的path变量,向其中添加CPPUNITHOME\lib,从新启动计算机,使设置生效。

1.3. 在Eclipse下安装CppUnit 

 CppUnit配置到Eclipse平台实际是通过项目中加入头文件实现的,将CppUnit 的头文件的目录添加到编译所用环境变量中.

1.4.在MinGW / Eclipse / window 下安装

  这个组合是为了在window的环境下使用gcc来编译CppUnit的测试代码。这里先简单介绍一下MinGW.

1.4.1MinGW简介(www.mingw.org)

一个自由使用和自由发布的Windows特定头文件和使用GNU工具集接口库的集合,支持生成的windows程序而不需要借助第三方运行时库。MinGW(MiniamalistGNU for Windows)是一些头文件和接口库的集合,该集合支持人们在没有第三方动态链接库的情况下使用GCC来生成Win32程序。在基本层上,MinGW是一组包含文件和接口库,其功能是允许控制台模式的程序使用MS标准C运行时库(MSVCTR.dll)。通过基本运行时,gcc编写的符合ANSI的控制台模式的程序可以使用C运行库扩展,MinGW的另一个组成部分W32API—是一组可以使用win32API的包含文件的和接口库。

提到MinGW,必然想到Cygwin:Cygnus Solutions开发的自由软件,嵌入式软件的开发的流行。Cygwin改进了gcc,gdb,gas,使其能够生成并解释win32的目标文件,然后再把这些工具移植到window,共享库(基于win32API编写了一个Unix系统库的模拟层),Unix主机交叉编译,逐步移植其他的工具。

在这个环境下安装和在Linux安装什么区别。

终于,所有的安装事项都结束了,在进入理论前使用一个例子实践一下。

2 CppUnit实例--来自参考[3]

/*Program:testcppunit.cpp -- a simple hellow example which use the cppunit tool*/
#include <iostream>
#include <cppunit/TestRunner.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
class Test : public CPPUNIT_NS::TestCase
{
    CPPUNIT_TEST_SUITE(Test);
    CPPUNIT_TEST(testHelloWorld);
    CPPUNIT_TEST_SUITE_END();
    public:
   	 void setUp(void) {}
   	 void tearDown(void) {}
    protected:
    	void testHelloWorld(void) { std::cout << "Hello, world!" << std::endl; }
};
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
int main( int argc, char **argv )
{
    // Create the event manager and test controller
    CPPUNIT_NS::TestResult controller;
    // Add a listener that colllects test result
    CPPUNIT_NS::TestResultCollector result;
    controller.addListener( &result );       
    // Add a listener that print dots as test run.
    CPPUNIT_NS::BriefTestProgressListener progress;
    controller.addListener( &progress );     

    // Add the top suite to the test runner
    CPPUNIT_NS::TestRunner runner;
    runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );
    runner.run( controller );
    return result.wasSuccessful() ? 0 : 1;
}
编译命令: gcc -o   testcppunit testcppunit.cpp -lcppunit (如果是VC/windows的话,使用cl 代替gcc--注意要配置cl的环境变量才可以在cmd命令行下使用)

在shell输入./testcppunit ,执行结果:

Test::testHelloWorldHello,world!

:OK

3 一些CppUnit的理论

1)CppUnit核心部分(core)

  • 基本测试类:Test,TestFixture,TestCase,TestSuite

  • 测试结果记录:SychronizedObject,TestListener,TestResult

  • 错误处理:TestFailure,SourceLine,Execption,NotEqualException

  • 断言:Asserter,TestAssert

2)输出部分(Ouput)

  • 基本部件:Outputter,TestResultCollector

  • 衍生类:TestOutputter,CompilerOutputer,XmlOutputer

3)辅助部分(Helper)

TypeInfoHelper,TestFactory,TestFactoryRegistry,NamedRegisters,TestSuiteFactory,

TesSuiteBuilder,TestCaller,AutoRegisterSuite,HelperMacros.

4)扩展部分(Extension)

TestDecorator,RepeatedTest,Orthodox,TestSetUp

5)监听者部分(Listener)

TestSucessListener,TextTestProgressListener,TextTestResult

6)界面部分(UI)

TestRunner(TextUI,MfcUI,QtUI)

7)移植(Portabilty):OStringStream

4 网上的关于CppUnit的一些资料的汇总

 a)CppUnit 快速使用指南:https://www.ibm.com/developerworks/cn/linux/l-cppunit/

 b)CppUnit源代码解读:http://morningspace.51.net/resource/cppunit/cppunit_anno.html

    其中百度文库上有一个关于这个源码解读的doc格式的资料:

    http://wenku.baidu.com/view/b7fcad4bcf84b9d528ea7ae1.html

 c)百度文库中还有其他类似的CppUnit的资料,但是不如上面的这两个质量高.

 d)还有一个资料就是CppUnit源码包中example以及相应的文档.

5. 后记--关于CppUnit 1.21.1源码安装的问题的探索

     源码安装时遇到问题首先是要看readme中没有没有介绍,然后看看INSTALL,FAQ,TODO中有没有解决方法,然后才到网上搜结果。

首先找到参考[3] 其中介绍了一个ldconfig命令---一个修改了/etc/ld.so.confl文件的后重来动态加载的相应动态链接库程序的路径的程序。参考[3]中描述的不适和我的机器,”修改/etc/ld.so.conf文件(动态链接库路径)并添加/usr/local/lib来增加动态加载的库的路径“,我的系统中/etc/ld.so.conf.d/*.conf中已经包含了/usr/local/lib路径

此外,还实践了这一句:”make install没有把头文件安装到/usr/include中去,此时还需要手工去复制,只要把include下面的cppunit目录复制到/usr/include下面就可以了,命令很简单,就不写了。实践命令是:

sudo cp -r cppunit /usr/include --- 这个其实也是有问题的,我后来使用locate命令在 /usr/local/iinclude中发现了cppunit目录。

其次是参考[4],我惊人的发现那个外国哥们遇到的问题和我一样,看了下面的回复后,我以为是因为没有安装libdl.so的问题,尝试安装libc6libc6-dev(使用sudo apt-get install xxx),实际系统已经安装好了这两个库(基本构建库),看了各种奇怪的Linux发行版的路径,终于在/lib/i386-linux-gun/下发现了libdl.so.2库是存在的,为什么会编译错误,是路径的问题吗??找了一个程序实例使用一下libdl库。

/*Program:testlibdl.c -- this example test weather the libdl.so.2 is work or not*/
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
    void *handle;
    double (*desk)(char*);
    char *error;
    handle = dlopen ("/lib/libc.so.6", RTLD_LAZY);
    if (!handle) {
        fputs (dlerror(), stderr);
        exit(1);
    }
    desk= dlsym(handle, "Apply");
    if ((error = dlerror()) != NULL)  {
        fputs(error, stderr);
        exit(1);
    }
    dlclose(handle);
}

注:程序中dlopen,dlsym,dlclose这三个程序使用过了

编译命令:cc-o testlibdl testlibdl.c -ldl

执行./testlibdl结果

/lib/i386-linux-gnu/libc.so.6:undefined symbol: Apply

        虽然程序没干啥事,但是它使用libdl库的,并且没有出现连接错误。难道是因为库路径的问题?尝试了添加符号链接文件到/lib,/usr/lib这些目录下,错误依旧,就这样我已经消耗了2,3小时,就这样不断的编译,不断的查看Makefile文件(足足有800多行的Makefile文件,看的我头都大了)

最后,就在我快要放弃的时候,参考[5]中发现这样的话本人是安装的desktop-i386版本。make的时候提示dlopendlclose等函数找不到.检查上边的编译命令发现其中有-ldl选项,但是位置不对位置应该放到最后去而编译命令的最后一个是-lm.于是在出错的几个文件夹下面将Makefle中的-lm选项后面加上-ldl再执行make命令即可编过”

问题已经找到了,-ldl命令的位置的问题。因为-lm总是出现在最后,我就在所有编译问题的目录MakefileLIBS=-lm后面添加了一个-ldl选项,然后编译一下,遇到通过的就添加-ldl选项,终于都执行make通过了。

最后 sudo make install,cppunit安装到/usr/local/lib中。我们可以使用命令 ls /usr/local/lib/ |grep libcppunit 查看是否整个安装好了。如果安装好了,会出现下面这些库.

         libcppunit-1.12.so.1

libcppunit-1.12.so.1.0.0

libcppunit.a

libcppunit.la

libcppunit.so

在至此探索中发现libldl.so库是一个有意思的动态链接库。

Ps: Interface Libraries

NAME
       libdl - dynamic linking library
SYNOPSIS
       cc [ flag... ] file... -ldl [ library... ]
DESCRIPTION
       Historically,  functions in libdl provided for dynamic linking support.
       This functionality now resides in libc(3LIB).
       This library is maintained to provide backward compatibility  for  both
       runtime  and compilation environments. The shared object is implemented
       as a filter on the runtime  linker.  See  ld.so.1(1).  New  application
       development need not specify -ldl.
INTERFACES
       The  shared object libdl.so.1 provides the following public interfaces.
       See Intro(3) for additional information on shared object interfaces.
       dladdr                        dladdr1
       dlclose                       dldump
       dlerror                       dlinfo
       dlmopen                       dlopen
 dlsym

 6 .小结

   a)有些问题虽然解决方法很简单,但是,在遇到问题后想到这个简单的解决方法却不那么的容易。

   b)最难的是要找到问题在哪里,知道了问题在哪里后,很多事情都是可以解决的。现实是很多情况下,我们不知道问题在何处,因此需要探索,需要”撞墙“。

下一篇是关于覆盖工具的.

参考文献:

[7] 软件测试实验指导教程/蔡建平, 清华大学出版社, 2009.11

[1]Ubuntu安装CppUnit http://blog.sina.com.cn/s/blog_4901f88e0100nogf.html

[2]CppUnit on Ubuntu  http://ubuntuforums.org/showthread.php?t=683620

[3]Linux下的CppUnit 的HelloWorld手记 http://blog.csdn.net/hairetz/article/details/5622222

[4] stackoverflow网站上 libdl.so not found on Ubuntu EC2 instance
http://stackoverflow.com/questions/11352991/libdl-so-not-found-on-ubuntu-ec2-instance

[5]ubuntu 11.10 安装 cppunit  http://forum.ubuntu.org.cn/viewtopic.php?f=70&t=349118

[6] 百度词条 CppUnit:http://baike.baidu.com/view/4336315.htm


你可能感兴趣的:(单元测试,ubuntu,软件测试,12.04,CppUnit安装,libldl库问题)