【TestNGpp】C&C++测试框架TestNG++入门指导(xUnit简介,TestNG和JUnit的区别等)

    xUnit

xUnit框架改变了单元测试的历史,一时间,很多语言的多种单元测试框架蜂涌而至。

xUnit是各种代码驱动测试框架的统称,这些框架可以测试软件的不同单元,比如函数和类。xUni框架的主要优点是,它提供了一个自动化测试的解决方案,没必要多次编写重复的测试代码。https://wenku.baidu.com/view/966b775ccc7931b765ce155a.html

    发展至今,xUnit已经有很多年的历史了,炙手可热的JAVA测试框架JUnit也经历了JUnit2、JUnit3、JUnit4的发展历程,后来发展到了TestNG。

      身为中级语言的C/C++,虽然不具备JAVA语言的很多特性,比如反射,给测试框架开发带来一定困难,但它也毫不示弱,今年来出现了很多测试框架,比如CppUnit、UnitTest++、CppUTest、gtest、CxxTest等等,不仅如此,与Java世界的TestNG对应,C++世界中也有TestNG++(又称testngpp),它具备很多优秀的特质,

比如:

(1)TestNG++支持任意字符作为用例名。gtest借助VC支持Unicode标识符,支持中文用例名,但这种方案存在固有缺陷,gcc是不支持标识符为Unicode字符串的,所以就无法使用这个特性,TestNG++巧妙的使用描述信息来标示用例,真正的用例标识符只是内部自动生成的毫无意义的名字,这使得用例可读性问题得到了很好的解决,而且这种方案完全是可以跨平台、跨编译器的。

(2)TestNG++支持Annotation、Tag等TestNG才具备的特征。

(3)TestNG++支持sandbox用例运行方式,每个用例都在独立的环境中运行,互不影响。(sandbox沙盘盒子。一个被隔离的程序,在里面做任务事件都不会影响到宿主程序。只能调用宿主开放的一些API。)

(4)TestNG++采用加载dll的方式运行用例,可以根据需要只加载需要测试的dll,避免了用例过滤的搜索时间。

(5)TestNG++的用例编写接口简单方便,把很多容易混淆的概念进行了巧妙的处理,避免使用者的记忆负担。比如:setup方法名字,各种不同的测试框架中有不同的定义,gtest中是SetUp,CppUnit中是setUp,TestNG++中把所有测试框架规定的关键字全作为宏封装起来,使用SETUP()宏即可。

(6)TestNG++使用CMake自动生成编译器对应的Makefile或者工程文件,支持几乎所有平台、所有编译器下的使用。
更多特性请参见:http://code.google.com/p/test-ng-pp/wiki/ChineseUserManual

    从技术的角度讲,TestNG++与CxxTest类似,也采用了Python解析用例的方法,这是因为C++不支持反射,只能通过解析用例代码的方法来具备一定的反射能力,这使得使用者必须先安装Python(目前使用的是Python 2.6版本)。

 

    本文以VC2008为例介绍testngpp的安装和使用方法。

 

注:实际上,对于C++程序员来说,从零到Testngpp的一步,可以看做是敏捷实践和TDD思想的第一步(当然也有可能是读了一本书《TDD》或者《重构》心血来潮想要试试的第一步)。

 

准备活动:

 

1. 下载testngpp

下载地址:http://code.google.com/p/test-ng-pp/
该网站还有testngpp-msvc.pdf是很好的VC下使用testngpp的介绍文档,本文也是参考该文档实践成功之后所写。
另外,ChineseUserManual是很好的testngpp特性的介绍文档。
本文用到的工程类似的测试工程,网上也有下载:
http://code.google.com/p/testngpp-samples/
注:如果有些家庭网络和公司网络不能连接code.google.com的话,最好不要随便在搜索引擎里找testngpp的源码,比如在https://bitbucket.org/godsme/testng网站上下载的代码,不知为何,总是无法正确编译。
注:推荐使用testngpp1.1的版本进行编译和安装。
预留资源链接-->-------------------------------<--预留资源链接


2、下载cmake


注:cmake 的版本并无太多要求,从老到新应该都能用。


3、编译并安装testngpp


(1)运行CMake中的bin/cmake-gui.exe,设置源代码路径为testngpp-1.0根目录,设置CMake产生的文件放置在build目录中(build目录会自动创建)。
注:此处需要注意的是:需要安装python并且把python目录加入系统变量PATH中才可编译通过此处需要注意的是:需要安装python并且把python目录加入系统变量PATH中才可编译通过,configure之后Cmake会输出Python的版本和路径,

确保在编译之后不要再更改Python的版本,否则在用例编译过程中会导导致“ImportError:Bad magic number”类似的错误告警。

(2)点击Configure。

弹出选择编译器的对话框,选择VC2010。
(3)一段时间之后,配置完成。
我这里存在告警,但不影响使用。
(4)再点击一次Configure,很快提示配置完成,并且Generate按钮变得可用。
(5)点击Generate按钮,生成sln和vcproj工程。
(6)用VC2010打开testngpp.sln。
(7)按F7编译解决方案。
(8)在INSTALL上点右键,编译,就可以把testngpp安装到C:/Program Files/testngpp目录(该路径在cmake中可设置)。
注:以上步骤没有问题,我出错的两次分别是下错了代码和编译期间换了Python版本。

 

在项目中使用testngpp


一、被测工程


1、建立被测工程。
注意:
(1)工程类型为静态库。
(2)一般可以设置为不使用预编译头文件。
注:忘记修改不使用预编译头文件的话,可以在“属性-配置属性-C/C++-预编译头”选项中修改。
 

2、在被测工程目录下建立src和include目录。

注:此处创建src和include目录的主要目的是创建测试工程的时候可以方便包含,需要注意的是在被测工程内部也要包含这个目录,否则会造成编译不过(错误点)。

 

二、测试工程


1、建立测试工程。
注意:
(1)工程类型为动态库。
(2)创建为空的项目。
注:此处空的项目未对预编译头进行设定,可以按照前文修改去除预编译头。
2、创建文件AllTests.cpp并加入测试工程。
其内容为:
#include "Sample1Test.cc"
注:Sample1Test.cc是自动生成的、可编译运行的用例。
把它包含进AllTests.cpp比直接把它加入工程要好,避免每次自动生成Sample1Test.cc之后,都要重新加载该文件。
注:不听原作者的话,自己去试了试,如果不使用AllTest.cpp去包含Sample1Test.cc文件的话,每次重新编译测试工程都会被VS2010温馨提醒是否重载Sample1Test.cc文件,烦不胜烦,诚不余欺。

 

3、配置测试工程的头文件包含路径。


包括被测工程对外公开头文件的目录,以及testngpp头文件目录、testngpp使用到的第三方库boost目录(主要用了boost的typeof实现)。
4、把testngpp.lib链接到测试工程。


注:此处只看到了把testngpp.lib链接到测试工程,其实Sample1.lib也是需要链接到Smaple1Test工程中的,不过因为项目的创建顺序问题,其实Sample1Test创建的时候指向的工程目录和Sample1是相同的,所以默认就可以自动link,但是如果像我一样手痒改了路径的话,还需要手动把Sample1.lib链接到Sample1Test工程中(错误点)


5、配置Sample1Test运行时的命令行参数
命令:C:/Program Files/testngpp/bin/testngpp-runner.exe
参数:$(OutDir)/$(TargetName) -L"C:/Program Files/testngpp/testngpp/listener" -l"testngppstdoutlistener -c -v"
注:参数中第一个是测试工程编译成的dll文件名;-L表示测试结果listener的dll所在路径;-l 表示使用哪一种结果输出的listener。

注:更多的格式有如下可选(摘抄自Sample的README):
$(OutDir)\$(TargetName) -L"$(SolutionDir)..\..\testngpp\testngpp\listener" -l"testngppstdoutlistener -c" -s
 "-s" means running test in sandbox mode. Or,
 $(OutDir)\$(TargetName) -L"$(SolutionDir)..\..\testngpp\testngpp\listener" -l"testngppstdoutlistener -c" -l"testngppstdoutxmllistener result.xml"
 to a new listener "xml listener", the test result will be written to file "result.xml". Or,
 $(OutDir)\$(TargetName) -L"$(SolutionDir)..\..\testngpp\testngpp\listener" -l"testngppstdoutlistener -c -v"
 to change the TestNG++ Stdout Listener to verbose mode.
此外,如果Sample和SampleTest的路径没有包含关系的话,建议使用绝对路径代替$(OutDir)\$(TargetName)的相对路径。

6、配置测试工程的自定义生成规则,以便根据测试文件(.h)自动生成Sample1Test.cc。
 注:这是改动最多的地方,VS2010里已经找不到“自定义生成规则”的菜单了,反之多加了一个“属性管理器”的模块,用于管理属性和规则。

如下为原文:
(1)项目上右键,选择“自定义生成规则”。
(2)新建规则文件。
注:如果已经创建过testngpp generator规则,则只需要把它勾上即可。该规则创建一次之后,就可以在任意解决方案中使用,当然需要注意是否能直接使用,可能需要编辑规则中的输出文件名。
(3)填写新建规则的名称、文件名、规则文件存放路径。然后点击“添加生成规则”。
(4)生成规则填写为如下图所示的样子。
命令行需要填写为:python.exe "C:/Program Files/testngpp/testngpp/generator/testngppgen.pyc" -e gb2312 -o Sample1Test.cc [inputs]
(5)最后,把TestGenerator勾上即可,它就在测试工程中生效了,编译的时候就会自动生成Sample1Test.cc 。
在原文中的生成规则的主要目的是当VS2010编译到.h文件的时候,按照新修改的规则将h文件中的用例读取并转换为testgnpp认定的格式(类xml格式),在生成规则中指定了生成对象为“-o Sample1Test.cc”。

具体的做法:
找不到“自定义生成规则”的时候可以说人是很崩溃的,不过还好,绕过生成规则的方法,就是在预先生成事件中指定需要生成的用例文件,把生成规则做的事情固定化、具体化(看到公司的做法是用python做的一个小脚本,遍历了约定文件后缀“.hpp”的文件,一样的处理思路)。
在“属性-生成事件-预先生成事件”中填写命令:

python.exe "C:/Program Files/testngpp/testngpp/generator/testngppgen.pyc" -e gb2312 -o Sample1Test.cc "E:\TDDDev\TDDProject\Sample1Test\Sample1Test\TestBar.h"
命令的前半段与上文保持一致,Sample1Test.cc 为生成文件的名字,要和AllTest中包含的文件一致。最后的路径为测试所在的文件,此处不指定文件类型。

如果编译过程中出现错误


1>PreBuildEvent:
1>  'python.exe' 不是内部或外部命令,也不是可运行的程序


那么需要检查下python是否存在于环境变量PATH中(添加之后需要重启VS2010(错误点))。

如果显示:
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(103,5): error MSB3073: 命令“python.exe "C:/Program Files/testngpp/testngpp/generator/testngppgen.pyc" -e gb2312 -o Sample1Test.cc "E:\TDDDev\TDDProject\Sample1Test\Sample1Test\TestBar.h"
1>C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(103,5): error MSB3073: :VCEnd”已退出,代码为 1。
那么有很大的概率是①文件名和路径有误,②VS2010开发环境的IDE权限不足,③FIXTURE或class的定义大括号后没有“;”
--------------------- 

需要仔细检查(添加之后需要重启VS2010(错误点))。


7、把被测工程编译生成的.lib链接到测试工程的dll中。
可以简单的设置Sample1Test依赖Sample1即可。

三、向被测工程添加被测代码。


这里是把已有的CBar.h等四个文件添加到被测工程。(当然也可以是你想编写的任何内容)
注:走到这一步基本是一片通途。


四、向测试工程添加测试代码。


测试代码写在.h文件中

五、编译运行。


按F7编译整个解决方案,然后再按Ctrl+F5即可运行用例。
注:走到这发现显示一条用例都没执行的话,

回到编译自定义规则一栏重新来,应该输入用例所在文件的地方,一定是空的~。

如上,愿君顺利敏捷~

原文:

https://blog.csdn.net/sinojelly/article/details/5616671

2 https://blog.csdn.net/kingcat666/article/details/73477351 
 

 

TestNG的注解

 

在第三节中不知道大伙有没有这么一个问题:

问题:

成千上万个测试用例如何管理?
上节已经讲了如何通过Selenium来打开浏览器,但是有没有发现我们的所有脚本启动都得通过JAVA的main函数来启动,那么问题来了,如果我们一个方法就是一个测试用例,那么当我们有成千上百个测试用例需要被执行时,怎么办?难道都通过main函数把所有的方法都加进去?

答案:

我们需要一个可以组织管理我们测试用例的框架。可以是Junit也可以是TestNG,而我们后面的课程都会以TestNG为例,进行讲解。

TestNG 简介:

TestNG类似Junit或者NUnit,但是TestNG提供了更加强大,更加方便,更加灵活的并且是开源的测试框架。 它几乎可以用在我们所有的测试环节,单元测试,基础测试, end-to-end测试,功能测试等等。。。
官方网站:http://testng.org/doc/

TestNG 测试框架给我们提供了什么?

  • 提供强大的注释,方便测试人员的使用。
  • 支持数据驱动测试(DDT)
  • 支持并行测试
  • 可以灵活配置测试,强大的执行模式
  • 可生成多种测试报告
  • 等等

安装

TestNG其实是一个jar包,所以我们可以通过配置我们的Maven工程来下载对应jar包。 修改pom.xml文件,添加如下:

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.11</version>
    <scope>test</scope>
</dependency>

常用注解

@Test

标记一个类或方法作为测试的一部分。

标注一个类,则这个类里面是所有方法都将成为测试方法。

import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
@Test
public class TestNGDemo01 {

    public void test1(){
        System.out.print("这个是test1");
    }

    public void test2(){
        System.out.print("这个是test2");
    }

    public void test3(){
        System.out.print("这个是test3");
    }
}

通过IDEA直接运行,看到控制台运行结果:

image.png

标注一个方法,则该方法则为测试方法

如下面例子,我们只标注test1()和test2()为测试方法,我们再次执行这个类:

import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @Test
    public void test1(){
        System.out.println("这个是test1");
    }

    @Test
    public void test2(){
        System.out.println("这个是test2");
    }

    public void test3(){
        System.out.println("这个是test3");
    }
}

最后我们发现控制台只打印了test1()和test2(),test3()没被标注则不再是一个测试方法:

image.png

如何描述一个测试方法

有时我们需要描述一个测试方法是做什么用的,除了通过JAVA的注解描述外,@Test注解也提供了描述的方法:

    @Test(description = "这个是test1注解")
    public void test1(){
        System.out.println("这个是test1");
    }

结果不会对输出有任何影响,但却让人很容易知道这个测试方法是做什么的:

image.png

如何设置测试方法的超时时间

如果你担心一个测试方法因为某些原因卡着迟迟不执行结束或者你觉得某个流程如果多长时间内如果没法执行结束那就得去优化,那么我们可以强制设置一个测试方法最长的测试时间。

    @Test(timeOut = 2000)
    public void test2() throws InterruptedException {
        System.out.println("这个是test2");
        Thread.sleep(3000);
    }

如上代码,我们设置一个测试方法的timeOut 为2000毫秒,但是我们的测试方法体却要等待3000毫秒,所以这个测试方法,最后一定执行会抛出错误:

image.png

如何控制测试方法的执行顺序

在不做额外设置的情况下,测试方法的执行顺序是根据方法名的ASCII先后来执行的,例如下面的例子,我们把test2()放于test1()之前,然后执行这个测试类:

import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {
    @Test
    public void test2() throws InterruptedException {
        System.out.println("这个是test2");
        Thread.sleep(3000);
    }

    @Test
    public void test1(){
        System.out.println("这个是test1");
    }

    @Test
    public void test3(){
        System.out.println("这个是test3");
    }
}

执行结果如下,我们发现依旧test1()在test2()之前执行:

image.png

那么如果我们就想test2()在test1()之前执行呢?如下我们只需要给@Test加上“priorty”参数并设置顺序便可:

import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @Test(priority = 1)
    public void test2() throws InterruptedException {
        System.out.println("这个是test2");
        Thread.sleep(3000);
    }

    @Test(priority = 2)
    public void test1(){
        System.out.println("这个是test1");
    }

    @Test(priority = 3)
    public void test3(){
        System.out.println("这个是test3");
    }
}

运行结果:

image.png

测试方法相互依赖

写测试用例时,我们尽可能得不要去写相互依赖的测试用例,Case依赖的另一个Case,那么另一个Case只是你这个Case的前提条件,所以就算离开另一个Case,你这个Case也应该能独立运行,也就是说Case要保持原子性。
同样自动化代码组织起来的测试方法(测试用例)我们也应该做到原子性,但要是某些特殊场景非得做到Case间相互依赖咋办?看如下代码,通过给@Test添加“dependsOnMethods”参数解决:

import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @Test
    public void test2(){
        System.out.println("这个是test2");
    }

    @Test(dependsOnMethods = "test2")
    public void test1(){
        System.out.println("这个是test1");
    }

    @Test
    public void test3(){
        System.out.println("这个是test3"); 
    }

}

如上代码,我们单独运行test1(),如果不加入依赖,那么只会运行test1(),但是我已经加上依赖了,那么执行test1()之前,它一定会先执行test2(),而test3()则不会被运行到:

image.png

@Test 注解还可以更很多别的参数,我们后面会有用到再讲。

@BeforeClass

在调用当前类的第一个测试方法之前运行,注释方法仅运行一次。

@AfterClass

在调用当前类的第一个测试方法之后运行,注释方法仅运行一次

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @BeforeClass
    public void beforeClass() {
        System.out.println("这个是 BeforeClass");
    }

    @AfterClass
    public void afterClass() {
        System.out.println("这个是 AfterClass");
    }

    @Test
    public void test1() {
        System.out.println("这个是 test1");
    }

    @Test
    public void test2() {
        System.out.println("这个是 test2");
    }
}

我们整个类运行起来,查看运行结果如下,被@BeForeClass和@AfterClass标注的类我们只允许了一次,而且BeforeClass在所有的Test之前运行,AfterClass在所有的Test之后运行:

image.png

@BeforeTest

注释的方法将在属于<test>标签内的类的所有测试方法运行之前运行。

@AfterTest

注释的方法将在属于<test>标签内的类的所有测试方法运行之后运行。

import org.testng.annotations.*;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @BeforeClass
    public void beforeClass() {
        System.out.println("这个是 BeforeClass");
    }

    @AfterClass
    public void afterClass() {
        System.out.println("这个是 AfterClass");
    }

    @BeforeTest
    public void beforeTest() {
        System.out.println("这个是一个 BeforeTest");
    }

    @AfterTest
    public void afterTest() {
        System.out.println("这个是一个 AfterTest");
    }

    @Test
    public void test1() {
        System.out.println("这个是 test1");
    }

    @Test
    public void test2() {
        System.out.println("这个是 test2");
    }
}

执行结果,如下图,我们看到BeforeTest和AfterTest也都只执行了一次,而且BeforeTest比BeforeClass还早执行,同时AfterTest晚于AfterClass执行:

image.png

@BeforeMethod

注释方法将在每个测试方法之前运行。

@AfterMethod

注释方法将在每个测试方法之后运行。

import org.testng.annotations.*;

/**
 * Created by 米阳 on 2017/9/12.
 */
public class TestNGDemo01 {

    @BeforeClass
    public void beforeClass() {
        System.out.println("这个是 BeforeClass");
    }

    @AfterClass
    public void afterClass() {
        System.out.println("这个是 AfterClass");
    }

    @BeforeTest
    public void beforeTest() {
        System.out.println("这个是一个 BeforeTest");
    }

    @AfterTest
    public void afterTest() {
        System.out.println("这个是一个 AfterTest");
    }

    @BeforeMethod
    public void beforeMethod(){
        System.out.println("这是一个 BeforeMethod");
    }

    @AfterMethod
    public void afterMethod(){
        System.out.println("这是一个 AfterMethod");
    }

    @Test
    public void test1() {
        System.out.println("这个是 test1");
    }

    @Test
    public void test2() {
        System.out.println("这个是 test2");
    }
}

运行类结果如下,我们看到BeforeMethod在每个Test运行执行都执行一次,AfterMethod则在每个Test运行之后运行。同时BeforeMethod比BeforeClass和BeforeTest都后执行,先结束:

 

image.png

还有很多的注解,以后用到我们再讲。



作者:我在新博客等你I米阳
链接:https://www.jianshu.com/p/4eb4024aa2e0
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

posted on 2022-10-04 01:28  bdy  阅读(32)  评论(0编辑  收藏  举报

导航