当前位置: 首页 > news >正文

单元测试的心法分享

大家好,我是G探险者!

今天我们简单聊聊单元测试的哪些事儿~

两天时间我玩明白了单元测试的套路。

这里我分享一下思路。

在我眼里单元测试室什么?

请看这张草图:

单元测试主要关注单个代码单元(通常是类或方法)的逻辑正确性,而不是功能测试的全面性。具体来说:

单元测试的目的

  1. 验证逻辑路径:单元测试旨在验证代码逻辑中的不同路径是否按预期执行。这包括条件分支(如if-else语句)、循环、异常处理等。
  2. 隔离测试:通过mock或stub来隔离被测试的单元,使其不依赖外部资源(如数据库、网络服务)或其他复杂对象。
  3. 快速反馈:单元测试应该快速执行,提供即时的反馈,帮助开发者在早期发现并修复问题。
  4. 保证代码质量:通过覆盖不同的逻辑路径和边界情况,确保代码在各种情况下都能正确运行。

与功能测试的区别

  • 单元测试:专注于验证单个代码单元的内部逻辑,不要求模拟复杂的实际场景。变量值的准确性不是重点,重点是逻辑是否按预期执行。
  • 功能测试:验证整个系统或子系统的功能是否满足需求,通常在集成环境中进行,涉及实际的外部资源和复杂的交互。

单元测试中的Mock实践

  1. 分析需要mock的对象和行为

    • 确定哪些外部依赖(如数据库、网络服务)需要被mock。
    • 只mock那些必要的对象,保持测试的简洁性。
  2. 创建mock对象的方式

    • 使用@Mock注解或Mockito.mock()方法创建mock对象。
    • 可以使用@RunWith(MockitoJUnitRunner.class)MockitoAnnotations.initMocks(this)来初始化@Mock注解的字段。
  3. mock的目的

    • 隔离被测试单元,确保测试专注于目标代码逻辑。
    • 控制依赖对象的行为和状态,模拟各种异常和边界条件,验证代码的健壮性和正确性。
  4. mock对象和行为

    • 使用when().thenReturn()模拟方法返回特定值。
    • 使用when().thenThrow()模拟方法抛出异常。
    • 使用thenReturn()多次或thenAnswer()模拟连续调用时的不同结果。
    • 使用verify()方法验证方法的调用次数和顺序,确保逻辑执行的正确性。

这里我总结了一些些单元测试基本套路吧,整理一个模板。

分析方法

假设我们有一个类 MyClass 和其中的一个方法 myMethod。在分析该方法时,你需要考虑以下几个方面:

  1. 输入参数:方法接受哪些参数?
  2. 依赖对象:方法中使用了哪些类的实例?
  3. 行为动作:方法内部调用了哪些其他方法?是否有外部依赖,如数据库、网络调用等?
  4. 输出结果:方法返回什么?是否有副作用(如修改了类的状态、写入日志等)?

分析示例

假设 MyClass 的 myMethod 如下:

public class MyClass {private MyDependency dependency;public MyClass(MyDependency dependency) {this.dependency = dependency;}public String myMethod(String input) {String transformedInput = input.toUpperCase();boolean isValid = dependency.validate(transformedInput);if (isValid) {return "Valid: " + transformedInput;} else {return "Invalid: " + transformedInput;}}
}

分析步骤

  1. 输入参数input(字符串)
  2. 依赖对象MyDependency(通过构造函数注入)
  3. 行为动作:调用了 dependency.validate(transformedInput)
  4. 输出结果:返回一个字符串,形式为 "Valid: " + transformedInput 或 "Invalid: " + transformedInput

单元测试模板

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.mockito.runners.MockitoJUnitRunner;@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(MockitoJUnitRunner.class)
public class MyClassTest {@Mockprivate MyDependency mockDependency;@InjectMocksprivate MyClass myClass;@Beforepublic void setUp() {MockitoAnnotations.initMocks(this);}@Testpublic void testMyMethod_ValidInput() {// ArrangeString input = "test";String transformedInput = "TEST";when(mockDependency.validate(transformedInput)).thenReturn(true);// ActString result = myClass.myMethod(input);// AssertassertEquals("Valid: TEST", result);verify(mockDependency).validate(transformedInput);}@Testpublic void testMyMethod_InvalidInput() {// ArrangeString input = "test";String transformedInput = "TEST";when(mockDependency.validate(transformedInput)).thenReturn(false);// ActString result = myClass.myMethod(input);// AssertassertEquals("Invalid: TEST", result);verify(mockDependency).validate(transformedInput);}
}

模板解析

  1. 导入依赖:导入了Mockito和JUnit的静态方法。
  2. 测试类定义:定义了 MyClassTest 测试类。
  3. Mock对象:使用 @Mock 注解创建 MyDependency 的mock对象。
  4. 测试准备:在 setUp 方法中初始化mock对象,并创建 MyClass 实例。
  5. 测试方法:定义两个测试方法,分别测试myMethod 在 validate 方法返回 true 和 false 的情况下的行为。

注意事项

  • 测试覆盖:确保测试覆盖了所有可能的输入和边界情况。
  • 行为验证:使用 verify 方法验证依赖对象的方法调用情况。
  • 异常处理:如果方法可能抛出异常,编写相应的测试用例。

通过这个模板,你可以系统地分析并编写单元测试,确保测试的全面性和准确性。

题外话

当然现在idea 里面有相关的些单元测试的插件,比如Squaretest,或者你直接通过ChatGPT来写。但是你得知道原理。

相关文章:

单元测试的心法分享

大家好,我是G探险者! 今天我们简单聊聊单元测试的哪些事儿~ 两天时间我玩明白了单元测试的套路。 这里我分享一下思路。 在我眼里单元测试室什么? 请看这张草图: 单元测试主要关注单个代码单元(通常是类或方法&am…...

【python】多线程(3)queue队列之不同延时时长的参数调用问题

链接1:【python】多线程(笔记)(1) 链接2:【python】多线程(笔记)(2)Queue队列 0.问题描述 两个线程,但是不同延时时长,导致数据输出…...

Java开发常见基础问题

Java开发的多个方面,包括但不限于Java基础知识、多线程并发、JVM、框架使用、数据库、设计模式、网络编程等。 以下是一些常见的问题以及回答的方向: Java 开发技术常见问题(一) Java 基础知识 对象和类的区别是什么&#xff1…...

大数据组件doc

1.flink Apache Flink Documentation | Apache Flink 2.kafka Apache Kafka 3.hbase Apache HBase ™ Reference Guide 4.zookeeper ZooKeeper: Because Coordinating Distributed Systems is a Zoo 5.spark Overview - Spark 3.5.1 Documentation 6.idea组件(…...

Docker Hub 国内镜像源配置

Docker Hub 国内镜像源配置 Docker Hub 国内镜像源是指在国内境内提供 Docker 镜像服务的镜像源。由于国际网络带宽等问题,国内用户下载 Docker 镜像通常速度较慢。因此,为了解决这个问题,一些国内的公司和组织提供了 Docker 镜像的国内镜像…...

持续总结中!2024年面试必问 20 道 Kafka面试题(一)

一、Kafka 的基础概念有哪些? Kafka 是一个分布式流处理平台,由 LinkedIn 开发,并于 2011 年成为 Apache 软件基金会的一部分。以下是 Kafka 的一些基础概念: Broker: Kafka 集群由多个 Broker 组成,每个 Broker 存储…...

Linux共享内存创建和删除

最近项目中使用到了共享内存记录下 创建共享内存: 删除共享内存: 代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <u…...

微信小程序如何自定义tabbar

微信小程序自定义底部tabbar是一个提升用户体验和增加小程序个性化的重要功能。以下是自定义底部tabbar的步骤&#xff0c;以供参考&#xff1a; 一、自定义tabbar的重要性 微信小程序默认的底部导航栏&#xff08;tabbar&#xff09;样式和布局是固定的&#xff0c;开发者无…...

【并发程序设计】15.信号灯(信号量)

15.信号灯(信号量) Linux中的信号灯即信号量是一种用于进程间同步或互斥的机制&#xff0c;它主要用于控制对共享资源的访问。 在Linux系统中&#xff0c;信号灯作为一种进程间通信&#xff08;IPC&#xff09;的方式&#xff0c;与其他如管道、FIFO或共享内存等IPC方式不同&…...

【操作与配置】VS2017与MFC环境配置

【操作与配置】VS2017与MFC环境配置 概述 Visual Studio 是一款强大且多功能的集成开发环境&#xff08;IDE&#xff09;&#xff0c;适用于软件开发人员和团队。使用此应用程序&#xff0c;您可以构建和调试现代Web应用程序&#xff0c;并利用扩展帮助探索几乎任何编程语言。…...

遥感影像信息提取

刘老师&#xff08;副教授&#xff09;&#xff0c;来自双一流重点高校&#xff0c;长期从事GIS/RS/3S技术及其生态环境领域中的应用等方面的研究和教学工作&#xff0c;并参与GIS的二次开发&#xff0c;发表多篇sci论文&#xff0c;具有资深的技术底蕴和专业背景。 专题一&am…...

LRU算法

文章目录 LRU算法LRU 如何实现LinkedHashMap来实现的LRU算法的缓存HashMap实现LRU算法的缓存 LRU算法 LRU&#xff08;Least Recently Used&#xff09;算法可以使用哈希表和双向链表来实现。哈希表用于快速查找数据&#xff0c;双向链表用于记录数据的访问顺序。以下是LRU算法…...

JVM运行时数据区 - 程序计数器

运行时数据区 Java虚拟机在执行Java程序的过程中&#xff0c;会把它管理的内存划分成若干个不同的区域&#xff0c;这些区域有各自的用途、创建及销毁时间&#xff0c;有些区域随着虚拟机的启动一直存在&#xff0c;有些区域则随着用户线程的启动和结束而建立和销毁&#xff0…...

1.JAVA小项目(零钱通)

一、说明 博客内容&#xff1a;B站韩顺平老师的视频&#xff0c;以及代码的整理。此项目分为两个版本&#xff1a; 面向过程思路实现面向对象思路实现 韩老师视频地址&#xff1a;【【零基础 快速学Java】韩顺平 零基础30天学会Java】 https://www.bilibili.com/video/BV1fh4…...

Redis这一篇就够了

一.概述 Redis是什么&#xff1f; Redis是远程服务字典服务&#xff0c;是一个开源的使用ANSI C语言编写&#xff0c;支持网络&#xff0c;可基于内存亦可持久化的日志型&#xff0c;Key-Value数据库&#xff0c;并提供多种语言的API。 redis会周期性把更新的数据写入磁盘或把…...

Java web应用性能分析之【jvisualvm远程连接云服务器】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客 Java web应用性能分析之【java进程问题分析工具】-CSDN博客 前面整理了java进程问题分析和分析工具&#xff0c;现在可以详细看看jvisualvm的使用&#xff0c;一般java进程都是部署云服务器&#xff0c;或者托管IDC机…...

springboot发送短信验证码,结合redis 实现限制,验证码有效期2分钟,有效期内禁止再次发送,一天内发送超3次限制

springboot结合redis发送短信验证码,实现限制发送操作 前言(可忽略)实现思路正题效果图示例手机号不符合规则校验图成功发送验证码示例图redis中缓存随机数字验证码&#xff0c;2分钟后失效删除redis缓存图验证码有效期内 返回禁止重复发送图验证码24小时内发送达到3次&#xf…...

【Python】使用 Pandas 统计每行数据中的空值

缘分让我们相遇乱世以外 命运却要我们危难中相爱 也许未来遥远在光年之外 我愿守候未知里为你等待 我没想到为了你我能疯狂到 山崩海啸没有你根本不想逃 我的大脑为了你已经疯狂到 脉搏心跳没有你根本不重要 &#x1f3b5; 邓紫棋《光年之外》 在数据分析…...

1pannel部署onenav导航容器编排模板

onenav导航 1pannel部署onenav导航容器编排模板 networks:1panel-network:external: true services:onenav:container_name: onenavimage: helloz/onenav:latestlabels:createdBy: Appsnetworks:- 1panel-networkports:- 127.0.0.1:{port}:80environment:- TZAsia/Shanghaivol…...

linux--实时性优化

linux--实时性优化 1 介绍2 实时性需求3 代表性实时系统4 嵌入式系统嵌入式软件系统结构处理器时钟节拍多任务机制任务调度方式任务调度算法时间片调度算法优先级调度算法基于优先级的时间片调度算法 5 cyclictest 测试工具命令说明命令分析参数含义 6 linux 实时性改进某版本上…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

Docker 本地安装 mysql 数据库

Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker &#xff1b;并安装。 基础操作不再赘述。 打开 macOS 终端&#xff0c;开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...