java,白盒测试 Codecover(覆盖测试)、Junit、Ant
概述
白盒测试是对系统结构、源代码的测试
开发过程中测试方法:单元测试、覆盖测试
Code cover(Java/COBOL覆盖测试)
- 熟悉 Codecover的 Standalone工作模式
- 掌握使用Ant工具辅助测试的方法
- 学习使用 Eclipse插件进行测试
Junit
- Junt简介
- 版本3和版本4的比较
- 类
WordDealUtil
测试
code cover
- 支持的语言:
java/COBOL
- 工作原理
通过在源代码中插入检测指令,实现对源代码的重新编排
在运行编排之后的代码,实现对代码运行时的覆盖测试 - 编排(修改源代码)
- compile(可执行程序)
- 运行测试(黑盒测试方法)----人工执行
- 分析日志(对log文件处理)
- 生成报告
SimpleJavaApp 覆盖测试
- 打开Eclipse,导入“SimpleJavaApp”工程
- 在Eclipse的“File” 菜单,选择“Import” 选项
- 在“General”分类中选择 “Existing Projects into Workspace” ,浏览SimpleJavaApp源文件所在路径
- 导入到工作空间。
- 安装配置CodeCover
- 设置环境变量–变量名:CODECOVER_HOME 值:指向CodeCover的安装路径
- –将CODECOVER_HOME加入到Path变量中
%CODECOVER_HOME%
没有bin文件夹
编排:
- 编排是指在源程序中插入额外的代码,以获得程序在执行时行为的信息。
codecover instrument --root-directory SimpleJavaApp/src --destination SimpleJavaApp/instrumentedSrc --container SimpleJavaApp/test-session-container.xml --language java --charset UTF-8
-
命令执行结束后,新的、经过编排的源代码将出现在指定的位置:SimpleJavaApp/instrumentedSrc
-
此外,还将生成一个包含有源代码静态信息的容器文件:SimpleJavaApp/test-session-container.xml
-
•选项root-directory 指向将要被编排的源代码的*包路径。
•选项 destination 指向编排后生成的源代码的路径。
•选项container 指向测试会话容器文件,该文件中包含编排代码的静态信息,即收集的覆盖数据。
•选项language 用来表明被编排源代码所使用的 开发语言。
•选项charset 用来表明源代码的字符集。
编译:
- 编排后,需要对经过编排的源代码进行编译。在
instrumentedSrc
目录下执行如下命令:javac -encoding UTF-8 -Xlint:unchecked org\codecover\simplejavaapp\SimpleJavaApp.java
执行:
java org.codecover.simplejavaapp.SimpleJavaApp
- 执行结束后,将在当前目录自动生成一个覆盖日志文件。该文件中记录了程序运行过程中的覆盖测试数据。
分析覆盖测试结果:
-
运行如下命令,将从覆盖日志文件中提取信息填充到测试会话容器文件中
codecover analyze --container SimpleJavaApp/test-session-container.xml --coverage-log SimpleJavaApp/instrumentedSrc/coverage-log-2020-06-09-22-45-38-472.clf --name TestSession1 --comment "The first test session"
-
•选项container指向在编排过程中创建的测试会话容器文件,覆盖日志文件中提取的覆盖数据将插入到该文件中。
•选项coverage-log 指向执行编排程序时生成的覆盖日志文件。
•选项name 定义测试会话的名字。
•选项comment 是一个可选项,为本次测试会话提供一个说明。
生成报告:
-
CodeCover为测试会话文件中包含的测试会话生成一个报告
-
•选项container 指向一个用来生成测试分析报告的测试会话容器文件。
•选项destination 指向将要生成的测试报告的初始HTML页面文件。
•选项session指向测试会话容器文件中一个测试会话的名字。
•选项template 指向用来生成报告所用的XML模板文件。
codecover report --container SimpleJavaApp/test-session-container.xml --destination SimpleJavaApp/SimpleJavaAppReport.html --session "TestSession1" --template %CODECOVER_HOME%/report-templates/HTML_Report_hierarchic.xml
查看报告内容
安装部署Ant
- 解压后,设置环境变量
成功:
- 根据实际情况修改
ant-build-codecover2.xml
文件头部变量声明信息(将该文件放在SimpleJavaApp目录下)
<property name="codecoverDir" value="codecover" /> <property name="sourceDir" value="src" /> <property name="instrumentedSourceDir" value="instrumented" /> <property name="mainClassName" value="Test" /> <property name="mainClassName2" value="Test2" />
codecoverDir:指向CodeCover的安装目录
F:/Testing/WhiteBox/codecover-batch-1.0sourceDir:被测目标程序的源文件目录
srcinstrumentedSourceDir:生成编排源代码的路径
instrumented
mainClassName:运行程序包含main方法的主类org.codecover.simplejavaapp.SimpleJavaApp
-
使用命令
–ant -f ant-build-codecover2.xml
进行测试 -
关闭程序窗口
查看测试报告report.html
eclipse插件模式
遇见问题
没有codecover这个选项
eclipse里面重新安装 Help–>install New Software–>Add
Name: CodeCover Update Site
Location: http://update.codecover.org/
-
进入 项目
properties
文件打开codecover
选中所有的复选框 -
打开包浏览视图,定位到“SimpleJavaApp” 工程的源文件目录(
src
),右键单击,选择Use For Coverage Measurement
项 -
打开
Run
菜单选择Run Configurations…
- •单击左上角“New launch configuration”按钮
- •单击左上角“New launch configuration”按钮
-
配置项目名为
SimpleJavaApp
单击“Search…”按钮,定位工程的主类。- 选择有main方法的主类。
- 选择有main方法的主类。
-
打开Arguments选项卡,在VM arguments输入框中填写如下内容
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-
在CodeCover选项卡中,检查“Run with CodeCover”复选框已经被选中,单击“Run”按钮
使用CodeCover透视图
-
•在Window菜单中选择Open Perspective下的Other…项
- 选择
codecover
- 选择
-
•在Live Notification在线通知视图中,键入 “localhost” 作为主机名,“1234” 作为端口。
•单击“Connect” 按钮,**在线通知功能。(连接前要保证程序处于运行状态)
-
填写测试用例OpenFile
•单击“Start Test Case” 按钮开始一个测试用例。
•在在线通知视图下发出现“Started test case.”字样。
-
在程序 运行测试用例
-
结束测试用例 End Test Case
等候显示结束测试会话
在eclipse查看测试数据
•结束应用程序,测试数据自动记录到本次测试会话中。
•单击“Save the active test session container”按钮保存本次测试数据。
-
导出测试报告
-
选择“Coverage Result Export”,单击“Next”按钮继续
选type为Report
输出目录下的.html文件(没有则自己创建一个)
保存后单击next
选择“xml”类型的模板文件
finish完成输出
打开输出目录打开html文件
JUnit
JUnit大大简化了开发人员执行单元测试的难度,特别是 JUnit 4 使用 Java 5 中的注解(annotation)使测试变得更加简单。
JUnit4不同于JUnit3的模型,JUnit3强制继承TestCase类,以函数命名规则来判断是否是测试;而JUnit4则使用元数据。
如果你使用JDK1.4,请用JUnit3;否则建议使用JUnit4,Annotation的方式更灵活
Junit3 和Junit4的区别
•以前所有版本的 JUnit 都使用命名约定和反射来定位测试。例如,下面的代码测试 1+1 等于 2:
import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; public void testAddition() { int z = x + y; assertEquals(2, z); } }
而Junit4中
•测试是由 @Test 注释来识别的,如下所示:import org.junit.Test; import junit.framework.TestCase; public class AdditionTest extends TestCase { private int x = 1; private int y = 1; @Test public void testAddition() { --Additiontest, Addition都是可以的 int z = x + y; assertEquals(2, z); } }
- SetUp 和 TearDown
- Unit 3 测试运行程序(test runner)会在运行每个测试之前自动调用 setUp() 方法。该方法一般会初始化字段,打开日志记录,重置环境变量,等等。
- 在 JUnit 4 中,您仍然可以在每个测试方法运行之前初始化字段和配置环境。然而,完成这些操作的方法不再需要叫做 setUp(),只要用 @Before 注释来指示即可
- 甚至可以用 @Before 来注释多个方法,这些方法都在每个测试之前运行。
- 清除方法与此类似 ,可以给它取一个更自然的名称,并用 @After
- 其他
- 比如类范围的 setUp() 和 tearDown() 方法 。任何用@BeforeClass 注释的方法都将在该类中的测试方法运行之前刚好运行一次,而任何用 @AfterClass 注释的方法都将在该类中的所有测试都运行之后刚好运行一次。
Junit4的Fixture
•在执行一个或者多个测试方法时需要的一系列公共资源或者数据,例如测试环境,测试数据等等。
在编写单元测试的过程中,您会发现在大部分的测试方法在进行真正的测试之前都需要做大量的铺垫——为设计准备 Fixture 而忙碌。
JUnit 专门提供了设置公共 Fixture 的方法,只需要:
- 使用注解 org.junit.Before 修饰用于初始化 Fixture 的方法。
- 使用注解 org.junit.After 修饰用于注销 Fixture 的方法。
- 保证这两种方法都使用 public void 修饰,而且不能带有任何参数。
JUnit 4 中引入了类级别的 Fixture 设置方法,编写规范如下:
- 使用注解 org,junit.BeforeClass 修饰用于初始化 Fixture 的方法。
- 使用注解 org.junit.AfterClass 修饰用于注销 Fixture 的方法。
- 保证这两种方法都使用 public static void 修饰,而且不能带有任何参数。
如何使用JUnit4进行单元测试
- @Before : setUp
- @After : tearDown
- @BeforeClass
- @AfterClass
- @Test : test*
异常以及时间测试
•注解 org.junit.Test 中有两个非常有用的参数:expected 和 timeout。
•参数 expected 代表测试方法期望抛出指定的异常,如果运行测试并没有抛出这个异常,则 JUnit 会认为这个测试没有通过。
@Test(expected=UnsupportedDBVersionException.class) public void unsupportedDBCheck(){ …… }
•参数 timeout指定被测试方法被允许运行的最长时间应该是多少,如果测试方法运行时间超过了指定的毫秒数,则 JUnit 认为测试失败。
@Test(timeout=1000) public void selfXMLReader(){ …… }
测试运行器
•测试运行器,JUnit 中所有的测试方法都是由它负责执行的。
•JUnit 为单元测试提供了默认的测试运行器。
•可以定制自己的运行器(所有的运行器都继承自 org.junit.runner.Runner),还可以为每一个测试类指定使用某个具体的运行器。
@RunWith(CustomTestRunner.class) public class TestWordDealUtil { …… }
Junit 4 实例
-
建立一个java工程–
coolJUnit
(使用jse1.6)-
建立类–WordDealUtil
package cn.edu.cuit.cooljunit; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 对名称、地址等字符串格式的内容进行格式检查或者格式化的工具类 * * @author Tiejun Wang */ public class WordDealUtil { /** * 将 Java 对象名称(每个单词的头字母大写)按照数据库命名的习惯进行格式化 * 格式化后的数据为小写字母,并且使用下划线分割命名单词 * * 例如:employeeInfo 经过格式化之后变为 employee_info * * @param name Java 对象名称 */ public static String wordFormat4DB(String name){ Pattern p = Pattern.compile("[A-Z]"); Matcher m = p.matcher(name); StringBuffer sb = new StringBuffer(); while(m.find()){ m.appendReplacement(sb, "_"+m.group()); } return m.appendTail(sb).toString().toLowerCase(); } }
-
-
在eclisp扩展Junit支持
•打开项目 coolJUnit 的属性页 -> 选择“Java Build Path”子选项 -> 点选“Add Library…”按钮 -> 在弹出的“Add Library”对话框中选择 JUnit,并在下一页中选择版本 4 后点击“Finish”按钮。
-
创建单元测试目录
- 通常不会将单元测试代码和被测试代码混在一起,这显然会照成混乱
- 因为单元测试代码是不会出现在最终产品中
- 建议分别为单元测试代码与被测试代码创建单独的目录,并保证测试代码和被测试代码使用相同的包名
-
创建测试类
package cn.edu.cuit.cooljunit; import static org.junit.Assert.assertEquals; import org.junit.Test; public class TestWordDealUtil { // 测试 wordFormat4DB 正常运行的情况 @Test public void wordFormat4DBNormal(){ String target = "employeeInfo"; String result = WordDealUtil.wordFormat4DB(target); assertEquals("employee_info", result); } }
测试方法需遵守的书写规范
-
测试方法必须使用注解 org.junit.Test 修饰。
-
测试方法必须使用 public void 修饰,而且不能带有任何参数。
-
测试方法中要处理的字符串为“employeeInfo”,按照设计目的,处理后的结果应该为“employee_info”。
-
assertEquals 是由 JUnit 提供的一系列判断测试结果是否正确的静态断言方法(位于类org.junit.Assert 中)之一,我们使用它将执行结果 result 和预期值“employee_info”进行比较,来判断测试是否成功。
-
-
运行测试用例
-
查看结果
- 绿色的进度条提示我们测试运行通过了。
- 现在就宣布代码通过了单元测试还为时过早。记住:您的单元测试代码不是用来证明您是对的,而是为了证明您没有错
- 因此单元测试的范围要全面,比如对边界值、正常值、错误值得测试;对代码可能出现的问题要全面预测,而这也正是需求分析、详细设计环节中要考虑的。
-
增加新的测试内容
package cn.edu.cuit.cooljunit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import org.junit.Test; public class TestWordDealUtil { // 测试 wordFormat4DB 正常运行的情况 @Test public void wordFormat4DBNormal(){ String target = "employeeInfo"; String result = WordDealUtil.wordFormat4DB(target); assertEquals("employee_info", result); } // 测试 null 时的处理情况 @Test public void wordFormat4DBNull(){ String target = null; String result = WordDealUtil.wordFormat4DB(target); assertNull(result); } // 测试空字符串的处理情况 @Test public void wordFormat4DBEmpty(){ String target = ""; String result = WordDealUtil.wordFormat4DB(target); assertEquals("", result); } // 测试当首字母大写时的情况 @Test public void wordFormat4DBegin(){ String target = "EmployeeInfo"; String result = WordDealUtil.wordFormat4DB(target); assertEquals("employee_info", result); } // 测试当尾字母为大写时的情况 @Test public void wordFormat4DBEnd(){ String target = "employeeInfoA"; String result = WordDealUtil.wordFormat4DB(target); assertEquals("employee_info_a", result); } // 测试多个相连字母大写时的情况 @Test public void wordFormat4DBTogether(){ String target = "employeeAInfo"; String result = WordDealUtil.wordFormat4DB(target); assertEquals("employee_a_info", result); } }
-
再次运行
- JUnit 运行界面提示我们有两个测试情况未通过测试
- 当首字母大写时得到的处理结果与预期的有偏差,造成测试失败(failure);
- 当测试对 null 的处理结果时,则直接抛出了异常——测试错误(error)。
- 显然,被测试代码中并没有对首字母大写和 null 这两种特殊情况进行处理
-
修改源码
JUnit 将测试失败的情况分为两种:failure 和 error。
• Failure 一般由单元测试使用的断言方法判断失败引起,它表示在测试点发现了问题;
• error 则是由代码异常引起,这是测试目的之外的发现,它可能产生于测试代码本身的错误,也可能是被测试代码中的一个隐藏的bug。
public static String wordFormat4DB(String name){ if(name == null){ return null; } Pattern p = Pattern.compile("[A-Z]"); Matcher m = p.matcher(name); StringBuffer sb = new StringBuffer(); while(m.find()){ if(m.start() != 0) m.appendReplacement(sb, ("_"+m.group()).toLowerCase()); } return m.appendTail(sb).toString().toLowerCase(); }
-
参数化测试
-
为准备使用参数化测试的测试类指定特殊的运行器 org.junit.runners.Parameterized。
-
为测试类声明几个变量,分别用于存放期望值和测试所用数据。
-
为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为 java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对。
-
为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。
-
编写测试方法,使用定义的变量作为参数进行测试。
package cn.edu.cuit.cooljunit; import static org.junit.Assert.assertEquals; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class TestWordDealUtilWithParam { private String expected; private String target; @Parameters public static Collection words(){ return Arrays.asList(new Object[][]{ {"employee_info", "employeeInfo"}, // 测试一般的处理情况 {null, null}, // 测试 null 时的处理情况 {"", ""}, // 测试空字符串时的处理情况 {"employee_info", "EmployeeInfo"}, // 测试当首字母大写时的情况 {"employee_info_a", "employeeInfoA"}, // 测试当尾字母为大写时的情况 {"employee_a_info", "employeeAInfo"} // 测试多个相连字母大写时的情况 }); } /** * 参数化测试必须的构造函数 * @param expected 期望的测试结果,对应参数集中的第一个参数 * @param target 测试数据,对应参数集中的第二个参数 */ public TestWordDealUtilWithParam(String expected , String target){ this.expected = expected; this.target = target; } /** * 测试将 Java 对象名称到数据库名称的转换 */ @Test public void wordFormat4DB(){ assertEquals(expected, WordDealUtil.wordFormat4DB(target)); } }
-
-
运行结果
上一篇: CentOS 6 SSH 免密登录
下一篇: NNI使用体验