JUnit单元测试
一、JUnit单元测试
1. 了解
要想知道一段程序的效果好不好,性能怎么样,能不能实现预期效果,往往要进行测试。根据测试的过程是否可解释、可观测分为黑盒测试 和 白盒测试,黑盒测试只关注被测试系统的输入和输出,不考虑内部实现,只验证功能是否符合需求;而白盒测试则要求测试人员了解代码结构和逻辑,通过测试内部路径和条件来验证程序的正确性。
JUnit单元测试就是白盒测试的一种,提供了注解(如@Test
)、断言(如assertEquals
)和测试套件的功能,使开发者能够有效地创建和管理测试用例。
2. JUnit实例
要想了解JUnit到底发挥了什么作用,还得到具体的应用中去感受.假如现在有两个方法add
和sub
,分别实现两个整数的加和减功能。
package com.junit;
public class JUnitDemo {
/*
* 加法
* */
public int add(int a, int b) {
return a + b;
}
/*
* 减法
* */
public int sub(int a, int b) {
return a - b;
}
}
可以看到在测试类中定义了一个临时变量结果result
,两段测试语句,要想运行一段就得把另外一段注释掉,虽然这里只有两个方法,
package com.junit;
public class JUnitTest {
public static void main(String[] args) {
//创建对象
JUnitDemo demo = new JUnitDemo();
//调用
int result= demo.add(1,2);
System.out.println(result);
int result= demo.sub(2,3);
System.out.println(result);
}
}
这时候JUnit
的作用就体现出来了,使用JUnit的一般步骤如下:
- 定义一个测试类(测试用例)
- 测试类名 一般叫做
ATest、CarTest……
(A,car都是被测试的类名),即测试类名+Test
- 测试包名 建议定为
xxx.xxx.xx.test
- 测试类名 一般叫做
- 定义测试方法(可以独立运行)
- 方法名 一般命名为
test+测试方法
,不过这种为老式的测试命名方式,现在可以命名为更加自由具体的方式. - 返回值 一般为
void
- 参数列表 一般为空
- 一般使用断言操作来处理结果
- 方法名 一般命名为
- 给方法加上
@test
(别忘了要导入对应依赖)
按照如上步骤进行操作,首先定义一个测试类,项目结构如下:
编写测试类代码如下
package com.niko.test;
import com.niko.junit.JUnitDemo;
import org.junit.jupiter.api.Test;
public class JUnitTest {
/*
* 测试add方法
* */
@Test
public void testAdd(){
JUnitDemo demo = new JUnitDemo();
int result = demo.add(1,2);
System.out.println("测试add方法成功,结果为"+result);
}
}
有时测试方法不会出现绿色的成功测试的提示,而是会出现红色的异常提示信息,比如下面的除零错误。
并且有时测试成功通过显示为绿色但是输出的结果并不是我们所想要的,比如在之前的add实现方法中代码逻辑写错了,加号写成了减号,但是测试不会报异常。这时就应该使用断言机制(Assert)来解决。
使用Assert同样要导入对应的包,值得注意的是,在JUnit 5中,Assert
类不再存在。取而代之的是,所有断言方法都位于org.junit.jupiter.api.Assertions
类中。也就是说原本的句子:
Assert.assertEquals(3,result);
变为
Assertions.assertEquals(3,result);
使用到的方法为:
如果add
方法返回的是a-b
,那么运行测试后结果如下:
改进后的测试方法如下:
package com.niko.test;
import com.niko.junit.JUnitDemo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.lang.AssertionError;
public class JUnitTest {
/*
* 测试add方法
* */
@Test
public void testAdd(){
JUnitDemo demo = new JUnitDemo();
int result = demo.add(1,2);
System.out.println("测试add方法成功,结果为"+result);
//断言 断言这个计算的结果为3
Assertions.assertEquals(3,result);
}
/*
* 测试sub方法
* */
@Test
public void testSub(){
JUnitDemo demo = new JUnitDemo();
int result = demo.sub(1,2);
System.out.println("测试sub方法成功,结果为"+result);
Assertions.assertEquals(-1,result);
}
}
3@Before
和@After
注解
如果有许多大体重复或者类似的方法需要测试,就会有许多重复的操作,比如上面的申请JUnitDemo临时对象和result临时变量,造成代码的大量重复,如何解决呢?这里就用到两个特殊的注解,在每个测试方法运行之前或之后执行一次相同的操作。
在JUnit中,@Before
和@After
注解用于在每个测试方法之前和之后执行特定的代码。这两者在JUnit 4中比较常用,而在JUnit 5中,它们被替换为@BeforeEach
和@AfterEach
。
前者常用于初始化测试环境、设置共享的对象或资源。例如,连接数据库或创建测试数据。后者常用于清理工作,如关闭资源、删除测试数据等。
最终的测试类代码优化如下:
package com.niko.test;
import com.niko.junit.JUnitDemo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class JUnitTest {
/*
* 而 demo = new JUnitDemo(); 是在已经声明的类成员变量demo上进行赋值,意味着这个变量在类的所有方法中都可以访问。
* */
private JUnitDemo demo;
@BeforeEach
public void setUp() {
demo = new JUnitDemo();
System.out.println("测试环境已设置");
}
@AfterEach
public void tearDown() {
System.out.println("测试结束\n");
}
/*
* 测试add方法
* */
@Test
public void testAdd() {
int result = demo.add(1, 2);
System.out.println("测试add方法成功,结果为:" + result);
Assertions.assertEquals(3, result, "加法结果应为3");
}
/*
* 测试sub方法
* */
@Test
public void testSub() {
int result = demo.sub(1, 2);
System.out.println("测试sub方法成功,结果为:" + result);
Assertions.assertEquals(-1, result, "减法结果应为-1");
}
}