单元测试
-
测试:是一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程。
-
阶段划分:单元测试(白盒)、集成测试(灰盒)、系统测试(黑盒)、验收测试(黑盒)
![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");}@Testpublic void testGetAge(){UserService userService = new UserService();Integer age = userService.getAge("100100200209291111");System.out.println(age);}@Testpublic void testGetGender(){UserService userService = new UserService();String gender = userService.getGender("10000000000000001X");System.out.println(gender);}@Testpublic void testGetGenderWithAssert(){UserService userService = new UserService();String gender = userService.getGender("10000000000000001X");//断言//Assertions.assertEquals("男",gender);Assertions.assertEquals("男",gender,"性别获取有问题");}@Testpublic 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;@BeforeEachpublic 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生成 仅供参考




