广州it培训机构,整站seo需要多少钱,免费手机网站商城,wordpress 评论插件【Spring Boot】034-Spring Boot 整合 JUnit 文章目录 【Spring Boot】034-Spring Boot 整合 JUnit一、单元测试1、什么是单元2、什么是单元测试3、为什么要单元测试 二、JUnit1、概述简介特点 2、JUnit4概述基本用法 3、JUnit5概述组成 4、JUnit5 与 JUnit4 的常用注解对比 三…【Spring Boot】034-Spring Boot 整合 JUnit 文章目录 【Spring Boot】034-Spring Boot 整合 JUnit一、单元测试1、什么是单元2、什么是单元测试3、为什么要单元测试 二、JUnit1、概述简介特点 2、JUnit4概述基本用法 3、JUnit5概述组成 4、JUnit5 与 JUnit4 的常用注解对比 三、Spring Boot 整合 JUnit1、Spring Boot 项目创建2、引入依赖3、外部库4、编写测试类5、运行结果截图6、SpringBootTest 本身支持依赖注入编写组件依赖注入 7、手动指定主启动类概述子包下可正常运行包外提示异常结构截图解决方案显式声明主启动类的位置 四、JUnit的断言机制1、概述2、基本使用3、组合条件断言4、异常抛出断言5、执行超时断言6、强制失败 五、前置条件检查机制1、概述2、代码演示3、运行结果截图 六、嵌套测试1、概述2、代码演示3、运行结果截图4、注意点 七、带入参的单元测试1、概述2、参数化测试3、基本类型概述代码演示测试结果截图 4、方法数据流返回概述代码演示测试结果截图 一、单元测试
1、什么是单元
单元最终能分解的尽可能小的、独立的、可执行的元素。
对于 Java 程序单元 类的方法。
2、什么是单元测试
对程序中的一个个单元进行测试看看是否能够正常使用、是否存在问题等。
3、为什么要单元测试
通过最小测试范围确定出一个功能单元是否正常可用通过单元测试的编写和执行可以在尽可能早期筛查、发现出一些问题。
二、JUnit
1、概述
简介
JUnit 是针对 Java 语言的一个经典单元测试框架它在测试驱动方面具有重大意义。JUnit 促进了“先测试后编码”的理论它强调测试数据与程序代码的配合关系使得开发者在程序开发中形成“编码一点测试一点”的过程这种编码习惯可以提高程序的正确性和稳定性进而提高开发者的产出效率减少后期排查错误的时间和精力。
特点
开放的资源框架用于编写和运行测试提供注释来识别测试方法提供断言来测试预期结果提供测试运行来运行测试允许编写代码更快并能提高质量测试代码编写优雅简洁花费时间较少测试代码可以自动运行并且检查自身结果并提供即时反馈没有必要人工梳理测试结果的报告测试代码可以被组织为测试套件包含测试用例甚至其他的测试套件…
2、JUnit4
概述
早期使用的 JUnit 版本为 4.x 这个版本对 jdk 的最低限制是 jdk 1.5 整个 JUnit 4 的代码被整合到一个 jar 包中使用时直接导入即可主流的 IDE 都有对 JUnit 的原生支持。
基本用法
编写一个类 声明一个无参无返回值方法 加上Test注解
使用 JUnit 4 的方式比较简单只需要编写一个类并声明一个无入参、无返回值的方法并标注 Test 注解即可被 IDE 识别且运行。
public class DemoTest {Testpublic void test() {System.out.println(DemoTest test run ......);}
}3、JUnit5
概述
一个单独 jar 包 一组 jar 包组合而成 支持用户定制
2017 年 9 月JUnit 5.0.0 正式发布它最低支持的 Java 版本是 Java 8 而且它的构建不再由一个独立的 jar 包构成而是以一组 jar 包共同组合而成。抛弃历史包袱通过支持扩展ExtensionJUnit 5 给用户提供了定制特殊的测试需求与方式。
组成
总的来说JUnit 5 由 3 个模块构成分别是 JUnit Platform 、JUnit Jupiter 、JUnit Vintage 。
JUnit Platform 基于 JVM 上启动测试框架的基础不仅支持 JUnit 的测试引擎也可以兼容其他的测试引擎JUnit Jupiter JUnit 5 的核心提供 JUnit 5 的新的编程模型内部包含一个测试引擎该测试引擎会基于 JUnit Platform 运行JUnit Vintage 兼容 JUnit 4 、JUnit 3 支持的测试引擎。
使用 JUnit 5 的方式跟 JUnit 4 并无太大区别同样是编写测试类并声明方法标注 Test 注解即可不再编写示例代码解释。
4、JUnit5 与 JUnit4 的常用注解对比
JUnit 5 相较于 JUnit 4 比较大的改动是注解的使用。下表展示了 JUnit 5 跟 JUnit 4 常用注解的对比。
注解意义JUnit 5JUnit 4标注一个测试方法无区别TestTest在每个测试方法前执行BeforeEachBefore在每个测试方法后执行AfterEachAfter在当前类中的所有测试方法之前执行BeforeAllBeforeClass在当前类中的所有测试方法之后执行AfterAllAfterClass禁用测试方法/类DisabledIgnore标记和过滤TagCategory声明测试工厂进行动态测试新增TestFactory/嵌套测试新增Nested/注册自定义扩展新增ExtendWith/
三、Spring Boot 整合 JUnit
1、Spring Boot 项目创建 2、引入依赖 项目创建完成后已经自动引入了spring-boot-starter-test ?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.17/versionrelativePath/ !-- lookup parent from repository --/parentgroupIdcom.zibo/groupIdartifactIdstudy-junit/artifactIdversion0.0.1-SNAPSHOT/versionnamestudy-junit/namedescriptionstudy-junit/descriptionpropertiesjava.version1.8/java.version/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependency!-- 创建项目后自动引入了该依赖 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationimagebuilderpaketobuildpacks/builder-jammy-base:latest/builder/image/configuration/plugin/plugins/build/project3、外部库 4、编写测试类
package com.zibo.studyjunit;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class StudyJunitApplicationTests {Testvoid contextLoads() {System.out.println(Hello World!);}}5、运行结果截图 6、SpringBootTest 本身支持依赖注入
编写组件
package com.zibo.studyjunit.component;import org.springframework.stereotype.Component;Component
public class HelloComponent {public String sayHello() {return Hello World!;}}依赖注入
package com.zibo.studyjunit;import com.zibo.studyjunit.component.HelloComponent;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class StudyJunitApplicationTests {Autowiredprivate HelloComponent helloComponent;Testvoid contextLoads() {helloComponent.sayHello();}}7、手动指定主启动类
概述
我们编写 SpringBoot 测试类时不可能把全部的测试类都放到与 SpringBoot 主启动类同包下当测试类一多整个 test 目录会非常混乱。为了方便寻找与管理我们还是需要将单元测试类也分包管理。但是请各位注意当 SpringBoot 测试类被放到其他包的时候运行 SpringBoot 测试类是有区别的。
子包下可正常运行
package com.zibo.studyjunit.demo;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class Demo1Test {Testvoid test1() {System.out.println(test1);}}包外提示异常
package demo;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class Demo2Test {Testvoid test2() {System.out.println(test2);}}结构截图 解决方案显式声明主启动类的位置
代码
package demo;import com.zibo.studyjunit.StudyJunitApplication;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest(classes StudyJunitApplication.class)
class Demo2Test {Testvoid test2() {System.out.println(test2);}}运行结果截图 四、JUnit的断言机制
1、概述
下面讲解 JUnit 5 中的经典使用方式断言。在 JUnit 4 中我们使用 Assert 类进行断言而到了 JUnit 5 中使用的类是 Assertions 类名变了使用方式却大差不差下面通过几个简单示例讲解 JUnit 5 的断言使用。
2、基本使用
Assertions 提供的最简单的断言方法包含比对两个值是否相等、两个对象是否是同一个、对象是否为 null 以及全场景通用的判断表达式的值为 true / false 。下面是一个简单的使用示例。 Testvoid testSimple() {// 一、两个值是否相等// 最简单的断言断言计算值与预期值是否相等int num 3 5;Assertions.assertEquals(num, 8);double result 10.0 / 3;// 断言计算值是否在浮点数的指定范围内上下浮动Assertions.assertEquals(result, 3, 0.5);// 如果浮动空间不够则会断言失败// 断言失败// Assertions.assertEquals(result, 3, 0.2);// 传入message可以自定义错误提示信息// 断言失败// Assertions.assertEquals(result, 3, 0.2, 计算数值偏差较大);// 二、两个对象是否是同一个// 断言两个对象是否是同一个Object o1 new Object();Object o2 o1;Object o3 new Object();Assertions.assertSame(o1, o2);// 断言失败// Assertions.assertSame(o1, o3);// 断言两个数组的元素是否完全相同String[] arr1 {aa, bb};String[] arr2 {aa, bb};String[] arr3 {bb, aa};Assertions.assertArrayEquals(arr1, arr2);// 断言失败// Assertions.assertArrayEquals(arr1, arr3);// 三、对象是否为 null// 断言对象是否为 nullObject o4 null;Object o5 new Object();Assertions.assertNull(o4);// 断言失败// Assertions.assertNull(o5);// 四、判断表达式的值为 true / false// 断言表达式的值为 trueint a 10;int b 20;Assertions.assertTrue(a b);// 断言表达式的值为 falseAssertions.assertFalse(a b);}3、组合条件断言
组合条件断言实际上是要在一条断言中组合多个断言要求这些断言同时、全部通过则外部的组合断言才能通过。这种设计有点类似于父子断言。 Testvoid testCombination() {// 组合条件断言只有当所有断言都成功时才会断言成功int a 10;int b 20;int c 30;// 断言 a b 并且 b cAssertions.assertAll(组合断言,() - Assertions.assertTrue(a b),() - Assertions.assertTrue(b c));}4、异常抛出断言
异常抛出的断言指的是被测试的内容最终运行时必定会抛出一个异常如果没有抛出异常则断言失败。 Testvoid testException() {// 断言抛出指定类型的异常Assertions.assertThrows(ArithmeticException.class, () - {int i 10 / 0;});}5、执行超时断言
执行超时断言是针对的是被测试代码的执行速度。 Testvoid testTimeout() {// 断言在指定时间内完成// 断言失败org.opentest4j.AssertionFailedError: execution timed out after 100 msAssertions.assertTimeoutPreemptively(java.time.Duration.ofMillis(100), () - {Thread.sleep(200);});}6、强制失败
类似于最原始的抛出异常的方式当满足某些条件时直接断言失败 Testvoid testFail() {if (java.time.ZonedDateTime.now().getHour() 12) {Assertions.fail();}}五、前置条件检查机制
1、概述
前置条件的检查机制同样应用在断言的场景中它指的是如果一个单元测试的前置条件不满足则当前的测试会被跳过后续的测试不会执行。使用前置条件检查机制可以避免一些无谓的测试逻辑执行从而提高单元测试的执行效率。
前置条件的检查使用的 API 是 Assumptions。
2、代码演示 Testvoid testAssumptions() {// 假设条件为 true 时才会执行后面的断言int num 3 5;Assumptions.assumeTrue(num 10);System.out.println(断言成功);// 假设条件为 false 时不会执行后面的断言Assumptions.assumeTrue(num 10);// 断言失败下面的代码不会执行System.out.println(断言失败);}3、运行结果截图 六、嵌套测试
1、概述
嵌套测试是 JUnit 5 的一个高级特性它支持我们在编写单元测试类时以内部类的方式组织一些有关联的测试逻辑。有关嵌套测试的演示代码在 JUnit 5 的官方文档中提供了一个非常全面的示例。
2、代码演示
package com.zibo.studyjunit.demo;import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;import java.util.EmptyStackException;
import java.util.Stack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class TestingAStackDemo {StackObject stack;// 测试用例使用new关键字实例化堆栈Testvoid isInstantiatedWithNew() {new Stack();}Nestedclass WhenNew {BeforeEachvoid createNewStack() {// 在每个测试方法之前创建一个新的堆栈实例stack new Stack();}// 测试用例堆栈在刚创建时是否为空TestDisplayName(is empty)void isEmpty() {assertTrue(stack.isEmpty());}// 测试用例在空栈上执行pop操作是否抛出EmptyStackException异常TestDisplayName(throws EmptyStackException when popped)void throwsExceptionWhenPopped() {assertThrows(EmptyStackException.class, () - stack.pop());}NestedDisplayName(after pushing an element)class AfterPushing {String anElement an element;BeforeEachvoid pushAnElement() {// 在堆栈中推入一个元素stack.push(anElement);}// 测试用例在推入元素后堆栈是否不再为空TestDisplayName(it is no longer empty)void isNotEmpty() {assertFalse(stack.isEmpty());}// 测试用例在推入元素后执行pop操作是否返回推入的元素并使堆栈为空TestDisplayName(returns the element when popped and is empty)void returnElementWhenPopped() {assertEquals(anElement, stack.pop());assertTrue(stack.isEmpty());}}}}3、运行结果截图 4、注意点
官方提供的测试代码都是可以执行通过的从这段测试代码中需要各位了解的几个关键特性
单元测试类可以通过编写内部类并标注 Nested 注解表明内部类也是一个单元测试类内部的单元测试类可以直接使用外部的成员属性且可以利用外部定义的 BeforeEach 、BeforeAll 、AfterEach 、AfterAll 等前后置逻辑注解标注的方法外部的单元测试无法利用内部类定义的前后置逻辑注解。
七、带入参的单元测试
1、概述
JUnit 5 中的一个重要特性是支持单元测试方法的参数依赖注入这也打破了我们已有的认知。通常我们编写的测试方法是不能有方法入参的但是 JUnit 5 允许我们在编写单元测试方法中予以声明方法入参。默认情况下 JUnit 5 支持以下几个参数类型的依赖注入
TestInfo 内部组装了当前单元测试所属的 Class 、Method 以及对应的展示名DisplayName等RepetitionInfo 如果一个方法被标注了 RepeatedTest 或者该方法是一个 BeforeEach / AfterEach 方法则可以拿到 RepetitionInfo 的信息可以通过 RepetitionInfo 获取到当前重复信息以及相应的RepeatedTest的重复总数TestReporter 注入 TestReporter 后可以获得数据发布能力可以向测试结果中注册一些特殊的数据这些数据可以被 TestExecutionListener 获取到。
2、参数化测试
参数化测试是 JUnit 5 中提高单元测试效率的重要手段它通过给单元测试方法传入特定的参数可以使得 JUnit 在执行单元测试时逐个参数来检验和测试这样做的好处是更加规整和高效地执行单元测试。
参数化测试支持我们使用如下的方式赋予参数
基本类型8 种基本数据类型 String Class 枚举类型自定义的枚举CSV 文件可传入一个 CSV 格式的表格文件使用表格文件中的数据作为入参方法的数据返回可以通过一个方法返回需要测试入参的数据流的形式返回。
3、基本类型
概述
在使用参数化测试时标注的注解不再是 Test 取而代之的是 ParameterizedTest 另外还需要声明需要传入的数据对于简单的基本类型而言使用 ValueSource 注解即可指定。
代码演示
package com.zibo.studyjunit.demo;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.context.SpringBootTest;SpringBootTest
class ParameterizedTestDemo {ParameterizedTestValueSource(strings {aa, bb, cc})void testSimpleParameterized(String value) {System.out.println(value);Assertions.assertTrue(value.length() 3);}}测试结果截图 4、方法数据流返回
概述
参数化测试最吸引人的点是可以引用一个方法来实现测试数据的参数化既然可以在一个方法中构造单元测试的入参数据那么完全可以从数据库 / 缓存等任意位置加载数据并构造为流的形式返回。以此法编写的参数化测试具有极大的灵活度和自由度。
代码演示 ParameterizedTestMethodSource(dataProvider)// MethodSource(getInteger)void testDataStreamParameterized(Integer value) {System.out.println(value);Assertions.assertTrue(value 10);}private static StreamInteger dataProvider() {return Stream.of(1, 2, 3, 4, 5);}// 不能用这种方式会报错// 返回值必须是StreamT或者StreamArguments// private static Integer getInteger() {// return 1;// }private static StreamArguments getInteger() {return Stream.of(Arguments.of(1), Arguments.of(2), Arguments.of(3));}测试结果截图