JUnit 5和Mockito进行单元测试!

news2024/11/15 19:32:57

  1. JUnit 5 基础

  JUnit 5是最新的JUnit版本,它引入了许多新特性,包括更灵活的测试实例生命周期、参数化测试、更丰富的断言和假设等。

  1.1 基本注解

  @Test:标记一个方法为测试方法。

  @BeforeEach:在每个测试方法之前执行。

  @AfterEach:在每个测试方法之后执行。

  @BeforeAll:在所有测试方法之前执行一次(必须是静态方法)。

  @AfterAll:在所有测试方法之后执行一次(必须是静态方法)。

  @DisplayName:定义测试类或测试方法的自定义名称。

  @Nested:允许将测试类分组到更小的测试类中。

  @ParameterizedTest:进行参数化测试。

  1.2 断言(Assertions类)

  Assertions 类是JUnit 5中用于断言的核心类,提供了一系列静态方法来验证测试条件是否满足预期。

  assertEquals(expected, actual):验证两个对象是否相等。如果不等,测试失败。

  assertTrue(boolean condition):验证条件是否为真。如果为假,测试失败。

  assertFalse(boolean condition):验证条件是否为假。如果为真,测试失败。

  assertNull(Object object):验证对象是否为null。如果不为null,测试失败。

  assertNotNull(Object object):验证对象是否不为null。如果为null,测试失败。

  assertThrows(Class<T> expectedType, Executable executable):验证执行executable是否抛出了expectedType类型的异常。如果没有抛出或抛出其他类型的异常,测试失败。

  assertAll(Executable... executables):同时执行多个断言,如果所有断言都成功,则测试通过;如果任何一个断言失败,所有失败的断言都会被报告。

  assertSame(expected, actual):验证两个对象是否为同一个对象(使用==比较)。如果不是,测试失败。

  assertNotSame(unexpected, actual):验证两个对象是否不是同一个对象(使用==比较)。如果是,测试失败。

  assertTimeout(Duration timeout, Executable executable):验证执行executable是否在给定的时间内完成。如果执行超时,测试失败。

  1.3  Assumptions 类

  Assumptions 类提供了基于某些条件判断是否执行测试的能力。如果假设失败(即条件不满足),当前测试会被跳过,而不是失败。以下是一些常用的Assumptions方法:

  assumeTrue(boolean assumption):如果假设为真,则继续执行测试;如果假设为假,测试被跳过。

  assumeFalse(boolean assumption):如果假设为假,则继续执行测试;如果假设为真,测试被跳过。

  assumingThat(boolean assumption, Executable executable):如果假设为真,则执行给定的executable(可以是一个测试方法);无论假设结果如何,测试都会继续执行,但executable只在假设为真时执行。

  2.Mockito 基础

  Mockito是一个流行的Java mocking框架,用于在隔离环境中测试代码,通过模拟依赖来确保测试的独立性。

  基本注解:

  @Mock:创建一个模拟对象。

  @InjectMocks:创建一个实例,其字段或构造器依赖将被@Mock注解的模拟对象自动注入。

  @Spy:可以创建一个真实的对象,并在需要时对它的某些方法进行模拟。

  @Captor:用于捕获方法调用的参数。

  常用方法:

  mock(Class<T> classToMock):创建一个类的模拟对象。这是创建模拟对象的基础。

  when(T methodCall):当你想模拟一个方法调用的返回值时使用。与thenReturn一起使用,可以指定一个方法调用应该返回什么值。

  thenReturn(T value):与when方法一起使用,用于指定方法调用的返回值。

  doReturn(Object toBeReturned):一个替代thenReturn的方法,用在当你需要模拟void方法或在spy对象上进行模拟时。

  verify(T mock):用于验证某个模拟对象的某个方法是否被调用,以及调用的次数。

  any():在设定模拟行为(如when)或验证(如verify)时,用于表示任何类型和值的参数。

  eq(T value):用于指定方法调用时期望的具体参数值。

  doNothing():用于模拟void方法时,指定该方法不执行任何操作。

  doThrow(Throwable... toBeThrown):用于模拟方法调用时抛出异常。

  spy(T object):创建一个真实对象的“间谍”或“spy”。这允许你在真实对象上“监视”方法调用,同时还能够覆盖某些方法的行为。

  ArgumentCaptor<T>:用于捕获方法调用时传递的参数,以便后续进行断言。

  times(int wantedNumberOfInvocations):与verify方法一起使用,用于指定某个方法被调用的具体次数。

  never():与verify一起使用,用于验证某个方法从未被调用过。

  示例

  假设我们有一个PaymentService类,它依赖于PaymentProcessor接口:

  public class PaymentService {      private PaymentProcessor processor;         public PaymentService(PaymentProcessor processor) {          this.processor = processor;      }         public boolean process(double amount) {          return processor.processPayment(amount);      }  }  下面是如何使用JUnit 5和Mockito来测试PaymentService类:  import org.junit.jupiter.api.Test;  import org.junit.jupiter.api.extension.ExtendWith;  import org.mockito.Mock;  import org.mockito.junit.jupiter.MockitoExtension;  import static org.mockito.Mockito.*;  import static org.junit.jupiter.api.Assertions.*;     @ExtendWith(MockitoExtension.class)  public class PaymentServiceTest {         @Mock      PaymentProcessor processor;         @Test      public void testProcessPayment() {          // 设置          PaymentService service = new PaymentService(processor);          double amount = 100.0;          when(processor.processPayment(amount)).thenReturn(true);             // 执行          boolean result = service.process(amount);             // 验证          assertTrue(result);          verify(processor).processPayment(amount);      }  }

  在这个例子中,我们使用@Mock来创建PaymentProcessor的模拟对象,并使用when(...).thenReturn(...)来定义当调用processPayment方法时应返回的值。然后,我们执行process方法,并使用assertTrue来验证结果是否符合预期。最后,我们使用verify来确认processPayment方法是否被正确调用。

  3.JUnit 5 进阶用法

  参数化测试(Parameterized Tests)

  参数化测试允许你使用不同的参数多次运行同一个测试。这对于需要验证多种输入条件的方法特别有用。

  @ParameterizedTest  @ValueSource(strings = {"Hello", "JUnit"})  void withValueSource(String word) {      assertNotNull(word);  }

  动态测试(Dynamic Tests)

  JUnit 5允许你动态生成测试,这些测试可以在运行时根据代码逻辑来决定。

  @TestFactory  Collection<DynamicTest> dynamicTests() {      return Arrays.asList(          dynamicTest("Add test", () -> assertEquals(2, Math.addExact(1, 1))),          dynamicTest("Multiply Test", () -> assertEquals(4, Math.multiplyExact(2, 2)))      );  }

  嵌套测试(Nested Tests)

  使用@Nested注解,你可以将相关的测试组织在一起作为一个组在外层测试类中运行。​​​​​​​

  @Nested  class WhenNew {      @Test      void isEmpty() {          assertEquals(0, new ArrayList<>().size());      }      @Nested      class AfterAddingAnElement {          @Test          void isNotEmpty() {              List<Object> list = new ArrayList<>();              list.add(new Object());              assertEquals(1, list.size());          }      }  }

  超时测试

  JUnit 5允许你为测试设置超时时间,确保测试在给定时间内完成。如果超出指定时间,测试将失败。​​​​​​​

  @Test  @Timeout(value = 500, unit = TimeUnit.MILLISECONDS)  void timeoutTest() {      // 模拟一个耗时的操作      // 如果操作超过500毫秒,则测试失败  }

  重复测试

  如果你想对一个测试方法进行多次执行以确保其稳定性或寻找潜在的偶发问题,可以使用@RepeatedTest注解。​​​​​​​

  @RepeatedTest(5)  void repeatTest() {      // 这个测试会运行5次  }

  条件执行

  JUnit 5提供了多种条件执行测试的方法,这些方法可以基于不同的条件来决定是否执行某个测试,例如操作系统类型、环境变量或Java版本。​​​​​​​

  @Test  @EnabledOnOs(OS.WINDOWS)  void onlyOnWindows() {      // 仅在Windows操作系统上运行  }  @Test  @EnabledIfSystemProperty(named = "user.name", matches = "yourUserName")  void onlyForSpecificUser() {      // 仅当系统用户名匹配时运行  }

  4.Mockito 进阶用法

  使用@Spy进行部分模拟

  有时你可能需要模拟类的某些方法,而保持其他方法的实际行为。@Spy注解允许你这样做。​​​​​​​

  @Spy  List<String> spyList = new ArrayList<>();  @Test  void testSpy() {      spyList.add("one");      spyList.add("two");      verify(spyList).add("one");      verify(spyList).add("two");      assertEquals(2, spyList.size()); // 实际调用方法      // 修改方法行为      doReturn(100).when(spyList).size();      assertEquals(100, spyList.size()); // 方法行为被改变  }

  参数捕获(Argument Captors)

  有时在验证方法调用时,你可能对方法调用的具体参数值感兴趣。@Captor注解和ArgumentCaptor类允许你捕获和检查这些值。​​​​​​​

  @Mock  List<String> mockList;  @Captor  ArgumentCaptor<String> argCaptor;  @Test  void argumentCaptorTest() {      mockList.add("one");      verify(mockList).add(argCaptor.capture());      assertEquals("one", argCaptor.getValue());  }

  连续调用的不同返回值

  有时候,你可能需要一个方法在连续调用时返回不同的值。Mockito允许你通过thenReturn()方法链来实现这一点。​​​​​​​

  when(mockList.size()).thenReturn(0).thenReturn(1);  assertEquals(0, mockList.size());  assertEquals(1, mockList.size());

  验证调用次数

  验证一个方法被调用了特定次数。​​​​​​​

  mockList.add("once");  mockList.add("twice");  mockList.add("twice");  verify(mockList).add("once");  verify(mockList, times(2)).add("twice");  verify(mockList, never()).add("never happened");

  模拟静态方法(需要Mockito 3.4.0及以上版本)

  从Mockito 3.4.0开始,你可以使用mockStatic来模拟静态方法。这是通过try-with-resources语句来实现的,以确保静态mock在使用后被正确关闭。​​​​​​​

  try (MockedStatic<UtilityClass> mockedStatic = mockStatic(UtilityClass.class)) {      mockedStatic.when(UtilityClass::someStaticMethod).thenReturn("mocked response");      assertEquals("mocked response", UtilityClass.someStaticMethod());      // 静态方法被模拟期间的行为  }  // 在这个块之外,静态方法恢复原有行为

  模拟final方法和类

  Mockito 2.x开始支持模拟final方法和类。为了启用这个功能,你需要在src/test/resources/mockito-extensions目录下创建一个名为org.mockito.plugins.MockMaker的文件,并在文件中添加一行内容:

  mock-maker-inline

  这样配置后,Mockito就可以模拟final类和方法了。

  使用BDDMockito进行行为驱动开发

  BDDMockito提供了一种基于行为驱动开发(BDD)的语法来编写Mockito测试,使得测试更加可读。​​​​​​​

  @Test  void bddStyleTest() {      // 给定      BDDMockito.given(mockList.size()).willReturn(2);      // 当      int size = mockList.size();      // 那么      BDDMockito.then(mockList).should().size();      assertEquals(2, size);  }

  5. @Mock 、@InjectMocks的原理

  @Mock

  · 原理:@Mock注解告诉Mockito框架为标注的字段生成一个模拟对象。这个模拟对象是动态生成的代理对象,它拦截对任何非final方法的调用,并允许测试者通过Mockito的API来配置这些调用的行为(例如返回特定的值或抛出异常)。

  · 如何工作:当测试初始化时(例如,通过使用MockitoAnnotations.initMocks(this)方法或JUnit 5的@ExtendWith(MockitoExtension.class)),Mockito会扫描测试类中所有使用@Mock注解的字段,并为它们创建模拟对象。这些模拟对象默认不执行任何实际的代码逻辑,它们的行为完全由测试者通过Mockito的API来控制。

  @InjectMocks

  · 原理:@InjectMocks注解用于自动将@Mock(或@Spy)注解创建的模拟对象注入到被注解的字段中。Mockito会尝试通过构造器注入、属性注入或setter方法注入的方式,将模拟对象注入到@InjectMocks标注的实例中。

  · 如何工作:

  构造器注入:Mockito首先尝试使用包含最多参数的构造器来创建实例。如果构造器的参数能够与已声明的模拟对象匹配,这些模拟对象将被用作构造器参数。

  属性注入:如果构造器注入不适用或不成功,Mockito会尝试直接设置实例中与模拟对象类型相匹配的属性。

  Setter注入:最后,如果属性注入不成功,Mockito会尝试通过调用匹配的setter方法来注入模拟对象。

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走! 

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2067578.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

69 H3C SecPath F1000 (系统模块介绍-2)

28-IRF 特性简介 IRF&#xff08;Intelligent Resilient Framework&#xff0c;智能弹性架构&#xff09;是一种软件虚拟化技术。它的核心思想是将多台设备连接在一起&#xff0c;进行必要的配置后&#xff0c;虚拟化成一台设备。使用这种虚拟化技术可以集合多台设备的硬件资源…

54. 螺旋矩阵【 力扣(LeetCode) 】

一、题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 二、测试用例 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入…

软件测试——自动化测试selenium

自动化测试 测试人员编写自动化测试脚本&#xff0c;维护并解决自动化脚本问题 自动化的主要目的就是用来进行回归测试 回归测试 常见面试题 ⾃动化测试能够取代人工测试吗&#xff1f; ⾃动化测试不⼀定⽐人工测试更能保障系统的可靠性&#xff0c;⾃动化测试是测试⼈员手…

图论 最短路

文章目录 单源最短路朴素Dijkstra代码 堆优化Dijkstra代码 Bellman-ford代码 spfaspfa求最短路代码 spfa判断负环代码 多源最短路Floyd代码 单源最短路 朴素Dijkstra 给定一个 n n n 个点 m m m 条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c;所有边权均为正…

vscode 阅读linux内核(vscode+clangd)

此插件曾在vim里用过&#xff0c;非常好用。 首先先在vscode 里下载clangd插件 这只是客户端&#xff0c;还需下载个服务器&#xff08;这在coc插件里也有说明&#xff09; sudo apt install clangd 下载完后可以 clangd --version 查看版本信息&#xff0c;如果能查看&#x…

回归预测|基于灰狼GWO优化BP神经网络多输入多输出的数据回归预测Matlab程序GWO-BP 含预测新数据程序

回归预测|基于灰狼GWO优化BP神经网络多输入多输出的数据回归预测Matlab程序GWO-BP 含预测新数据程序 文章目录 前言回归预测|基于灰狼GWO优化BP神经网络多输入多输出的数据回归预测Matlab程序GWO-BP 含预测新数据程序 一、GWO-BP多输出模型1. 原理2. GWO-BP模型流程步骤1: 初始…

jenkins最佳实践(一):jenkins安装与部署

各位小伙伴们大家好呀&#xff0c;我是小金&#xff0c;下面我将记录学习jenkins的系列文章与心得&#xff0c;一方面用于博主的自我记录&#xff0c;一方面如果能帮助到正在浏览这篇文章的小伙伴&#xff0c;那更好不过了&#xff0c;本篇文章主要讲述jenkins的安装以及安装je…

已经30岁了,想转行从头开始现实吗?什么样的工作算好工作?

我是29岁那年&#xff0c;完成从转行裸辞副业的职业转型。 如果你把职业生涯看成是从现在开始30岁&#xff0c;到你退休那年&#xff0c;中间这么漫长的30年&#xff0c;那么30岁转行完全来得及&#xff1b; 如果你觉得必须在什么年纪&#xff0c;什么时间内必须完成赚到几十…

框架——MyBatis查询(单表查询,多表联查)

目录 1.单表查询 2.多表查询 想查询student并且查询student所选择的专业major ①通过id查一个 ②不传入值直接查所有的学生列表 ③嵌套查询 想查询专业major并且查询该专业被哪些学生student选择 ①通过id查一个 ②不传入值直接查所有的专业列表 ③嵌套查询 3. 设置自动…

webpack打包优化方案

调试工具&#xff1a;安装webpack-bundle-analyzer打包可视化工具&#xff0c;可以看到打包文件大小&#xff0c;从而有针对性的优化。 npm install --save-dev webpack-bundle-analyzer。 方案一&#xff1a;将第三方依赖包使用cdn进行引入减小文件包体积&#xff08;例&…

Unity 编辑器-UGUI拓展Button,一个和原Button一样按钮⭐

拓展Button 需求实现1.创建继承自Button的类2.处理Inspector 显示问题3.处理在prafab中和hierarchy中创建按钮4.处理一些细节 完成 需求 想拓展一下UGUI的Button,找了几个帖子&#xff0c;只是能实现功能&#xff0c;但是用起来总有些不尽人意的地方&#xff0c;想办法处理一下…

针对防火墙IPSec业务不通或业务丢包问题,防火墙如何做流量统计、远程抓包、报文示踪

问题描述 针对防火墙IPSec业务不通或业务丢包问题&#xff0c;防火墙如何做流量统计、远程抓包、报文示踪 解决方案 1&#xff09;配置流统和远程抓包用的ACL&#xff1b; system [sysname] acl 3555 [sysname-acl-adv-3555] rule permit icmp source 10.82.100.215 0 destin…

Vue实现表格数据的增删改查

整体效果图&#xff1a; 一、创建表格数据 效果图&#xff1a; el-table组件&#xff1a;表格组件 <el-table:data"dataList"borderv-loading"dataListLoading"selection-change"selectionChangeHandle"style"width: 100%;">&l…

KISS(Keep It Sample,Stupid)[完整代码]

根据KISS原文它的伪随机数产生器的Period about 2^123&#xff0c;周期很长&#xff0c;并且来自于多个产生器的共同作用之下而得&#xff0c; 原文的这这句话很有意思&#xff0c;&#xff08;车轱辘压我脸上了&#xff09;一个人不好的时候&#xff0c;试一试两个人&#xff…

线段树的原理

1.如果知道两个子范围上的最值&#xff0c;通过比较就可以知道整个范围上的最值 2.如果知道两个子范围上分别出现的次数最多的数&#xff0c;但无法知道整个范围上出现最多的数 范围修改logn的前提&#xff1a;如果维护的是区域和&#xff0c;要把区域上的每个数字加上a&#…

【蓝桥杯集训100题】scratch绘制扇子 蓝桥杯scratch比赛专项预测编程题 集训模拟练习题第28题

scratch绘制扇子 蓝桥杯集训100题第28题模拟练习解析 此题曾经作为第十届省赛的真题考过 一、题目要求 以坐标&#xff08;0,0&#xff09;点为中心绘制一把扇子&#xff1b;扇面和扇把都是三分之一圆&#xff0c;扇面的半径 为 100 左右&#xff0c;扇把的半径为 20 左右。…

HTML实现2048小游戏

游戏概述 实现一个基本的2048游戏涉及综合运用HTML、CSS和JavaScript这三种关键技术。 HTML用于构建游戏的结构框架&#xff0c;包括游戏容器、网格布局以及可能的用户交互元素&#xff08;如按钮或得分显示&#xff09;。 CSS则负责美化游戏界面&#xff0c;通过样式表定义网格…

培训班和科班出生有什么区别

IT业的萌新来啦 每到毕业季 总有大量萌新走进职场 IT圈子的程序员 有的是科班出生 比如 计算机科学与技术、软件工程、大数据技术 有的是相关专业出生的 比如 信息安全、网络工程、物联网工程等等 除此之外 还有各种其他专业转行过来的 文理不限、专业不限 科班出生…

mydump 文件拆分 mysqldumpsplitter

mydump 文件拆分 如何将mysqldump的输出拆分为较小的文件&#xff1f; 要将mysqldump的输出拆分为较小的文件&#xff0c;可以使用–max-allowed-packet和–single-transaction选项。 使用–max-allowed-packet选项设置每个查询允许的最大数据包大小。这将确保mysqldump在执行…

精通 Stable Diffusion 调优秘籍

一、Stable Diffusion 调优概览 Stable Diffusion 作为一款强大的 AI 绘画工具&#xff0c;其调优具有至关重要的意义。通过合理的调优&#xff0c;可以显著提升图像生成的质量、速度和准确性&#xff0c;满足用户更加多样化和精细化的需求。 调优主要涵盖了多个方面。首先是模…