单元测试的重要性
- 什么是单元测试
单元测试是对软件组成单元进行测试,其目的是检验软件基本组成单位的正确性,测试的对象是软件设计的最小单位:函数。(维基百科)
- 单元测试的好处:
- 减少Bug率,防止被公司扣绩效;
- 更新代码时,减少重复的工作
- 可以极速地进行回归测试
- 快速定位Bug,配合使用Debug
单元测试做什么?
- 接口功能性测试: 接口功能的正确性,即保证接口能够被正常调用,并输出有效数据!
例如:是否被顺利调用\参数是否符合预期 - 局部数据结构测试:保证数据结构的正确性
例如:变量是否有初始值或在某场景下是否有默认值\变量是否溢出 - 边界条件测试:测试
变量无赋值(null)
变量是数值或字符
主要边界:最大值,最小值,无穷大
溢出边界:在边界外面取值+/-1
临近边界:在边界值之内取值+/-1
字符串的边界,引用 "变量字符"的边界
字符串的设置,空字符串
字符串的应用长度测试
空白集合
目标集合的类型和应用边界
集合的次序
变量是规律的,测试无穷大的极限,无穷小的极限 - 异常模块测试:(缺陷测试),后续处理模块测试:是否包闭当前异常或者对异常形成消化,是否影响结果!
TDD、ATDD、BDD&RBE
在目前比较流行的敏捷开发模式(如极限编程、Scrum方法等)中,推崇“测试驱动开发(Test Driven Development,TDD)” 测试在先、编码在后的开发实践。
- 在代码层次,在编码之前写测试脚本,可以称为单元测试驱动开发(Unit Test Driven Development,UTDD)
-
在业务层次,在需求分析时就确定需求(如用户故事)的验收标准,即验收测试驱动开发(Acceptance Test Driven Development,ATDD)。
UTDD从根本上改变了开发人员的编程态度,开发人员不能在像过去那样随意写代码,要求写的每行代码都是有效的代码,写完所有的代码就意味着真正完成了编码任务。
TDD一改以往的破坏性测试的思维方式,测试在先、编码在后,更符合“缺陷预防”的思想。
JUnit简介
JUnit 是用于编写和运行可重复的自动化测试的开源测试框架,这样可以保证我们的代码按预期工作。JUnit 可广泛用于工业和作为支架(从命令行)或IDE(如 IDEA)内单独的 Java 程序。
- 断言测试预期结果。
- 测试功能共享通用的测试数据。
- 测试套件轻松地组织和运行测试。
- 图形和文本测试运行。
JUnit 用于测试:
- 整个对象
- 对象的一部分 - 交互的方法或一些方法
- 几个对象之间的互动(交互)
JUnit 特点
- JUnit 是用于编写和运行测试的开源框架。
- 提供了注释,以确定测试方法。
- 提供断言测试预期结果。
- 提供了测试运行的运行测试。
- JUnit 测试让您可以更快地编写代码,提高质量
- JUnit 是优雅简洁。它是不那么复杂以及不需要花费太多的时间。
- JUnit 测试可以自动运行,检查自己的结果,并提供即时反馈。没有必要通过测试结果报告来手动梳理。
- JUnit 测试可以组织成测试套件包含测试案例,甚至其他测试套件。
- Junit 显示测试进度的,如果测试是没有问题条形是绿色的,测试失败则会变成红色。
JUnit 注解
@BeforeClass 全局只会执行一次,而且是第一个运行
@Before 在测试方法运行之前运行
@Test 测试方法
@After 在测试方法运行之后允许
@AfterClass 全局只会执行一次,而且是最后一个运行
@Ignore 忽略此方法
@AfterClass和BeforeClass即是为了满足测试中,那些体积非常大,但只要一次初始化的代码块!
测试方法必须是静态
注意:编写测试类的原则:
①测试方法上必须使用@Test进行修饰
②测试方法必须使用public void 进行修饰,不能带任何的参数
③新建一个源代码目录来存放我们的测试代码,即将测试代码和项目业务代码分开
④测试类所在的包名应该和被测试类所在的包名保持一致
⑤测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖
⑥测试类使用Test作为类名的后缀(不是必须)
⑦测试方法使用test作为方法名的前缀(不是必须)
第一个JUnit
@Test
public void sayHello() {
App app = new App();
String result = app.sayHello("girl");
}
JUnit 断言
断言是编程术语,表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真,可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言而在部署时禁用断言。同样,程序投入运行后,最终用户在遇到问题时可以重新启用断言。
使用断言可以创建更稳定、品质更好且 不易于出错的代码。当需要在一个值为 false 时中断当前操作的话,可以使用断言。单元测试必须使用断言(Junit/JunitX)。
常用断言方法
断言 | 描述 |
---|---|
void assertEquals([String message], expected value, actual value) | 断言两个值相等。值可能是类型有 int, short, long, byte, char or java.lang.Object. 第一个参数是一个可选的字符串消息 |
void assertTrue([String message], boolean condition) | 断言一个条件为真 |
void assertFalse([String message],boolean condition) | 断言一个条件为假 |
void assertNotNull([String message], java.lang.Object object) | 断言一个对象不为空(null) |
void assertNull([String message], java.lang.Object object) | 断言一个对象为空(null) |
void assertSame([String message], java.lang.Object expected, java.lang.Object actual) | 断言,两个对象引用相同的对象 |
void assertNotSame([String message], java.lang.Object unexpected, java.lang.Object actual) | 断言,两个对象不是引用同一个对象 |
void assertArrayEquals([String message], expectedArray, resultArray) | 断言预期数组和结果数组相等。数组的类型可能是 int, long, short, char, byte or java.lang.Object. |
测试断言效果
在之前的单元测试类中创建一个名为 testAssert 方法来查看断言效果
/**
* 测试断言
*/
@Test
public void testAssert() {
String obj1 = "junit";
String obj2 = "junit";
String obj3 = "test";
String obj4 = "test";
String obj5 = null;
int var1 = 1;
int var2 = 2;
int[] arithmetic1 = {1, 2, 3};
int[] arithmetic2 = {1, 2, 3};
assertEquals(obj1, obj2);
assertSame(obj3, obj4);
assertNotSame(obj2, obj4);
assertNotNull(obj1);
assertNull(obj5);
assertTrue("为真", var1 == var2);
assertArrayEquals(arithmetic1, arithmetic2);
}
Junit vs TestNG
- TestNG与JUnit的相同点:
使用annotation,且大部分annotation相同。
都可以进行单元测试(Unit test)。
都是针对Java测试的工具。 - TestNG与JUnit的不同点:
JUnit只能进行单元测试,TestNG可以进行单元测试,功能测试,端到端测试,集成测试等,主要是因为testNG
存在depends可以进行测试用例的组合;
TestNG需要一个额外的xml配置文件,配置测试的class、method甚至package。
TestNG的运行方式更加灵活:命令行、ant和IDE,JUnit只能使用IDE。TestNG有自己的命令行执行方式。
TestNG的annotation更加丰富和易懂,比如@ExpectedExceptions、@DataProvider等。
测试套件运行失败,JUnit 4会重新运行整个测试套件。TestNG运行失败时,会创建一个XML文件说明失败的测试,利用这个文件执行程序,就不会重复运行已经成功的测试。
Spring整合Junit
POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.suoron</groupId>
<artifactId>JunitSpring</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
单元测试类
@RunWith(SpringJUnit4ClassRunner.class) //表示整合JUnit4进行测试
@ContextConfiguration(locations = "classpath:spring-context.xml") //加载spring配置文件
public class AppTest2 {
private String flag;
@Resource
ApplicationContext context;