单元测试
-
测试:是一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。
-
阶段划分:单元测试(白盒)、集成测试(灰盒)、系统测试(黑盒)、验收测试(黑盒)
![image]()
-
测试方法:白盒测试、黑盒测试及灰盒测试
![image]()
-
单元测试:就是针对最小的功能单元(方法),编写测试代码对其正确性进行测试。
-
JUnit:最流行的Java测试框架之一,提供了一些功能,方便程序进行单元测试(第三方公司提供)。
对比main方法测试:


1.单元测试入门
- 在pom.xml中,引入JUnit的依赖
- 在test/java目录下,创建测试类,并编写对应的测试方法,并在方法上声明@Test注解。
- 运行单元测试(测试通过:绿色;测试失败:红色)

注意:JUnit单元测试类命名规范为:XxxxxTest【规范】。JUnit单元测试的方法,必须声明为 public void【规定】。
案例:使用JUnit,对UserService中业务方法进行单元测试

其中UserService中的代码为:
package com.itheima;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
public class UserService {
/**
* 给定一个身份证号,计算出该用户的年龄
* @param idCard 身份证号
*/
public Integer getAge(String idCard){
if (idCard == null || idCard.length() != 18) {
throw new IllegalArgumentException("无效的身份证号码");
}
String birthday = idCard.substring(6, 14);
LocalDate parse = LocalDate.parse(birthday, DateTimeFormatter.ofPattern("yyyyMMdd"));
return Period.between(parse, LocalDate.now()).getYears();
}
/**
* 给定一个身份证号,计算出该用户的性别
* @param idCard 身份证号
*/
public String getGender(String idCard){
if (idCard == null || idCard.length() != 18) {
throw new IllegalArgumentException("无效的身份证号码");
}
return Integer.parseInt(idCard.substring(16,17)) % 2 == 1 ? "男" : "女";
}
}
可以通过身份证号计算用户的年龄和性别
UserServiceTest中对其进行功能测试

测试通过,计算出了年龄。
2.断言&常见注解

对于身份证号,倒数第二位表示性别,如果为奇数则为男性,偶数则为女性。

如图可知,倒数第二位是1,测试也通过了,但是逻辑上应该为男,这说明不报错不代表代码没问题。这时候就要用到断言。
2.1、断言
-
JUnit提供了一些辅助方法,用来帮我们确定被测试的方法是否按照预期的效果正常工作,这种方式称为断言。
![image]()
提示:上述方法形参中的最后一个参数 msg ,表示错误提示信息,可以不指定(有对应的重载方法)。
测试性别:

测试通过

测试不通过,期望是男,但实际是女,说明逻辑上出现了错误,去相应方法中检查错误。
小结
1.在JUnit测试单元中,为什么要使用断言?
-
单元测试方法运行不报错,不代表业务方法没问题。
-
通过断言可以检测方法运行结果是否和预期一致,从而判断业务方法的正确性
-
Assertions.assertXxxx(...)
2.2、常见注解
-
在JUnit中还提供了一些注解,还增强其功能,常见的注解有以下几个:
![image]()
package com.itheima;
import org.junit.jupiter.api.*;
/**
* 测试类
*/
public class UesrServiceTest {
@BeforeAll //在所有的单元测试方法运行之前,运行一次
public static void beforeAll(){
System.out.println("before All");
}
@AfterAll //在所有的单元测试方法运行之后,运行一次
public static void afterAll(){
System.out.println("after All");
}
@BeforeEach //在每一个单元测试方法运行之前,都会运行一次
public void beforeEach(){
System.out.println("before Each");
}
@AfterEach //在每一个单元测试方法运行之后,都会运行一次
public void afterEach(){
System.out.println("after Each");
}
@Test
public void testGetAge(){
UserService userService = new UserService();
Integer age = userService.getAge("100100200209291111");
System.out.println(age);
}
@Test
public void testGetGender(){
UserService userService = new UserService();
String gender = userService.getGender("10000000000000001X");
System.out.println(gender);
}
@Test
public void testGetGenderWithAssert(){
UserService userService = new UserService();
String gender = userService.getGender("10000000000000001X");
//断言
//Assertions.assertEquals("男",gender);
Assertions.assertEquals("男",gender,"性别获取有问题");
}
@Test
public void testGetGenderWithAssert2(){
UserService userService = new UserService();
//断言
Assertions.assertThrows(IllegalArgumentException.class,()->{
userService.getGender(null);
});
}
}
结果:

/**
* 参数化测试
*/
@ParameterizedTest
@ValueSource(strings = {"10000000000000001X","10000000000000003X","10000000000000005X"})
public void testGetGender2(String idCard){
UserService userService = new UserService();
String gender = userService.getGender(idCard);
//断言
Assertions.assertEquals("男",gender,"性别获取有问题");
}

用DisplayName还可以给测试类命名

2.3、企业开发规范
package com.itheima;
// 只保留Junit 5的导入,删除Junit 4的import org.junit.Test
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; // Junit 5的Test注解
/**
* 测试类
*/
@DisplayName("用户信息测试类")
public class UserService2Test {
private UserService userService;
@BeforeEach
public void setUp(){
userService = new UserService();
}
/**
* 测试获取性别 - null值
*/
@Test // 此处已修正为Junit 5的@Test
@DisplayName("获取性别-null值")
public void testGetGender1(){
Assertions.assertThrows(IllegalArgumentException.class, () -> {
userService.getGender(null);
});
}
/**
* 测试获取性别 - 空串
*/
@Test
@DisplayName("获取性别-空串")
public void testGetGender2(){
Assertions.assertThrows(IllegalArgumentException.class, () -> {
userService.getGender("");
});
}
/**
* 测试获取性别 - 长度不足
*/
@Test
@DisplayName("获取性别-长度不足")
public void testGetGender3(){
Assertions.assertThrows(IllegalArgumentException.class, () -> {
userService.getGender("110");
});
}
/**
* 测试获取性别 - 超出长度
*/
@Test
@DisplayName("获取性别-长度超出")
public void testGetGender4(){
Assertions.assertThrows(IllegalArgumentException.class, () -> {
userService.getGender("100000200010110111100000");
});
}
/**
* 测试获取性别 - 正常: 男
*/
@Test
@DisplayName("获取性别-正常男性身份证")
public void testGetGender5(){
String gender = userService.getGender("100000200010011011");
Assertions.assertEquals("男", gender);
}
/**
* 测试获取性别 - 正常: 女
*/
@Test
@DisplayName("获取性别-正常女性身份证")
public void testGetGender6(){
String gender = userService.getGender("100000200010011021");
Assertions.assertEquals("女", gender);
}
}

那么如何知道自己测试功能是否齐全


也可以借助ai生成 仅供参考





浙公网安备 33010602011771号