Java IDEA JUnit 单元测试

JUnit是一个开源的 Java 单元测试框架,它使得组织和运行测试代码变得非常简单,利用JUnit可以轻松地编写和执行单元测试,并且可以清楚地看到哪些测试成功,哪些失败

JUnit 还提供了生成测试报告的功能,报告不仅包含测试的成功率,还能统计被测试代码的覆盖率。通过进行单元测试,我们可以确保每个方法按照预期正确运行。

如果我们修改了某个方法的代码,只需要确保相应的单元测试通过,就可以认为修改是正确的。此外,测试代码本身也可以作为示例代码,用于演示如何调用该方法。

几乎所有的IDE工具都集成了JUnit,我们这里使用IDEA

参考 编写JUnit测试 - 廖雪峰的官方网站 (liaoxuefeng.com)

目录

编写JUnit单元测试

使用Fixture自动执行代码

异常测试

条件测试

参数化测试

编写JUnit单元测试

用递推的方法写一个计算n的阶乘的Java方法。

我们可以针对刚刚写的Java编写一个对应的测试代码对其进行测试,在IDEA中可以直接右击点击生成Junit测试。

点击确定生成一个FactorialTest.java文件。

这是JUnit会把带有@Test的方法识别为测试方法,因此需要给测试方法加上@Test注解,测试方法内部用assertEquals(1, Factorial.fact(1))表示期望Factorial.fact(1)返回1。

运行这个测试程序,JUnit就会给出成功的测试和失败的测试,还可以生成测试报告,不仅包含测试的成功率,还可以统计测试的代码覆盖率,即被测试的代码本身有多少经过了测试。

 Factorial.java

public class Factorial {public static long fact(long n) {long r = 1;for (long i = 1; i <= n; i++) {r = r * i;}return r;}
}

 FactorialTest.java

import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;public class FactorialTest {@Testvoid testFact() {assertEquals(1, Factorial.fact(1));assertEquals(2, Factorial.fact(2));assertEquals(6, Factorial.fact(3));assertEquals(3628800, Factorial.fact(10));assertEquals(2432902008176640000L, Factorial.fact(20));}}

使用Fixture自动执行代码

Fixture是JUnit提供的编写测试前准备、测试后清理的固定代码,可以用于测试前和测试后自动执行代码。

先编写一个简单的实现加减法功能的Calculator代码。

但是测试的时候,需要先初始化对象,可以使用@BeforeEach和@AfterEach标记的方法,@BeforeEach标记的方法会在执行每个@Test的方法之前调用,而@AfterEach标记的方法会在执行每个@Test的方法之后调用,这样就可以通过@BeforeEach和@AfterEach标记来自动实现对象的生成和销毁。

然后再编写我们的测试代码。

运行测试代码,可以看到测试结果。

如果需要在所有@Test方法运行前后仅运行一次,那么可以使用@BeforeAll和@AfterAll对方法进行标记。

 Calculator.java

public class Calculator {private long n = 0;public long add(long x) {n = n + x;return n;}public long sub(long x) {n = n - x;return n;}
}

 CalculatorTest.java

import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;public class CalculatorTest {Calculator calculator;@BeforeEachpublic void setUp() {this.calculator = new Calculator();}@AfterEachpublic void tearDown() {this.calculator = null;}@Testvoid testAdd() {assertEquals(100, this.calculator.add(100));assertEquals(150, this.calculator.add(50));assertEquals(130, this.calculator.add(-20));}@Testvoid testSub() {assertEquals(-100, this.calculator.sub(100));assertEquals(-150, this.calculator.sub(50));assertEquals(-130, this.calculator.sub(-20));}
}

异常测试

对于可能抛出的异常进行测试是测试的重要环节,因此在编写JUnit测试的时候,除了正常的输入输出,还要特别针对可能导致异常的情况进行测试。

在计算阶乘的方法中增加对参数n的检查,如果n为负数,则直接抛出异常IllegalArgumentException。

在测试代码中,我们可以编写一个@Test方法专门测试异常,JUnit提供assertThrows函数来期望捕获一个指定的异常。

运行测试代码,可以看到测试结果。

 Factorial.java

public class Factorial {public static long fact(long n) {if (n < 0) {throw new IllegalArgumentException();}long r = 1;for (long i = 1; i <= n; i++) {r = r * i;}return r;}
}

 FactorialTest.java

import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.Test;public class FactorialTest {@Testvoid testFact() {assertEquals(1, Factorial.fact(1));assertEquals(2, Factorial.fact(2));assertEquals(6, Factorial.fact(3));assertEquals(3628800, Factorial.fact(10));assertEquals(2432902008176640000L, Factorial.fact(20));}@Testvoid testNegative() {assertThrows(IllegalArgumentException.class, () -> {Factorial.fact(-1);});}
}

条件测试

条件测试可以在满足某种条件下执行某些测试方法,不执行某些测试方法。

编写一个程序,该程序中的方法在Windows上跑和在Linux上跑的代码路径不同。

编写测试代码的时候,用@EnableOnOs标记方法,指定只有在特定系统下才执行该测试方法。

用@DisabledOnOs标记方法表示不在某个系统上执行该方法。

用@DisabledOnJre标记方法表示只能在高于特定Java版本的测试。

用@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")标记,表示只能在64位操作系统上执行的测试。

用@EnabledIfEnvironmentVariable标记方法表示需要传入环境变量DEBUG=true才能执行的测试。

运行测试代码,可以看到测试结果。

 Config.java

public class Config {public String getConfigFile(String filename) {String os = System.getProperty("os.name").toLowerCase();if (os.contains("win")) {return "C:\\" + filename;}if (os.contains("mac") || os.contains("linux") || os.contains("unix")) {return "/usr/local/" + filename;}throw new UnsupportedOperationException();}
}

 ConfigTest.java

import static org.junit.jupiter.api.Assertions.*;import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.*;public class ConfigTest {Config config;@BeforeEachpublic void setUp() {this.config = new Config();}@AfterEachpublic void tearDown() {this.config = null;}@Test@EnabledOnOs(OS.WINDOWS)void testWindows() {assertEquals("C:\\test.ini", config.getConfigFile("test.ini"));}@Test@EnabledOnOs({OS.LINUX, OS.MAC})void testLinuxAndMac() {assertEquals("/usr/local/test.cfg", config.getConfigFile("test.cfg"));}@Test@DisabledOnOs(OS.WINDOWS)void testOnNonWindowsOs() {// TODO: this test is disabled on windows}@Test@DisabledOnJre(JRE.JAVA_8)void testOnJava9OrAbove() {// TODO: this test is disabled on java 8}@Test@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")void testOnlyOn64bitSystem() {// TODO: this test is only run on 64 bit system}@Test@EnabledIfEnvironmentVariable(named = "DEBUG", matches = "true")void testOnlyOnDebugMode() {// TODO: this test is only run on DEBUG=true}
}

参数化测试

JUnit提供了一个@ParameterizedTest注解,用来进行参数化测试。参数化测试和普通测试稍微不同的地方在于,一个测试方法需要接收至少一个参数,然后,传入一组参数反复运行。

编写一个方法,该方法把字符串的第一个字母变为大写,后续字母变为小写。

在编写测试代码的时候,需要给出输入和预期输出,可以通过@MethodSource注解,它允许我们编写一个同名的静态方法来提供测试参数,编写一个静态方法testCapitalize返回了一组测试参数,每个参数都包含两个String,作为测试方法的两个参数传入。

还可以使用@CsvSource标记传入测试参数的方法,它的每一个字符串表示一行,一行包含的若干参数用 , 分隔。

如果测试数据很多,可以把测试数据提到一个独立的CSV文件中,标注上@CsvFileSource表示从CSV文件中读取数据。

由于JUnit只在classpath中查找指定的CSV文件,因此,test-capitalize.csv这个文件要放到src/main/resources目录下,内容格式如下图所示。

运行测试程序,测试结果如下图所示。

 StringUtils.java

public class StringUtils {public static String capitalize(String s) {if (s.length() == 0) {return s;}return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();}
}

StringUtilsTest.java

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;import static org.junit.jupiter.api.Assertions.*;public class StringUtilsTest {
//    @ParameterizedTest
//    @MethodSource
//    void testCapitalize(String input, String result) {
//        assertEquals(result, StringUtils.capitalize(input));
//    }
//
//    static List<Arguments> testCapitalize() {
//        return List.of( // arguments:
//                Arguments.of("abc", "Abc"), //
//                Arguments.of("APPLE", "Apple"), //
//                Arguments.of("gooD", "Good"));
//    }//    @ParameterizedTest
//    @CsvSource({"abc, Abc", "APPLE, Apple", "gooD, Good"})
//    void testCapitalize(String input, String result) {
//        assertEquals(result, StringUtils.capitalize(input));
//    }@ParameterizedTest@CsvFileSource(resources = {"test_capitalize.csv"})void testCapitalizeUsingCsvFile(String input, String result) {assertEquals(result, StringUtils.capitalize(input));}
}

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

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

相关文章

什么是PD快充诱骗芯片?它的原理是什么?

PD快充诱骗芯片&#xff0c;顾名思义&#xff0c;就是通过LDR6328Q PD取电芯片把pd适配器的电压给诱骗出来固定给后端设备供电。 PD诱骗芯片是受电端的一种PD协议芯片&#xff0c;它内置了PD通讯模块&#xff0c;通过与供电端&#xff08;如PD充电器&#xff09;的PD协议芯片握…

Ubuntu 安装MySQL以及基本使用

前言 MySQL是一个开源数据库管理系统&#xff0c;通常作为流行的LAMP&#xff08;Linux&#xff0c;Apache&#xff0c;MySQL&#xff0c;PHP / Python / Perl&#xff09;堆栈的一部分安装。它使用关系数据库和SQL&#xff08;结构化查询语言&#xff09;来管理其数据。 安装…

k8s之陈述式资源管理

1.kubectl命令 kubectl version 查看k8s的版本 kubectl api-resources 查看所有api的资源对象的名称 kubectl cluster-info 查看k8s的集群信息 kubectl get cs 查看master节点的状态 kubectl get pod 查看默认命名空间内的pod的信息 kubectl get ns 查看当前集群所有的命…

HTML实战演练之贪吃蛇美食大作战

导入&#xff1a; 一 &#xff1a;粉丝要求 今天一位小伙伴私信我说&#xff0c;想玩HTML贪吃蛇美食大作战&#xff0c;自己也是学HTML的&#xff0c;希望我能安排一下&#xff0c;那么好它来了 需知&#xff1a; 一&#xff1a;别着急先看需要知道的 要用HTML开发贪吃蛇美食…

很实用的ChatGPT网站——httpchat-zh.com

很实用的ChatGPT网站——http://chat-zh.com/ 今天介绍一个好兄弟开发的ChatGPT网站&#xff0c;网址[http://chat-zh.com/]。这个网站功能模块很多&#xff0c;包含生活、美食、学习、医疗、法律、经济等很多方面。下面简单介绍一些部分功能与大家一起分享。 登录和注册页面…

【Java EE初阶五】wait及notify关键字

1. wait和notify的概念 所谓的wait和notify其实就是等待、通知机制&#xff1b;该机制的作用域join类似&#xff1b;由于多个线程之间是随机调度的&#xff0c;引入wait和notify就是为了能够从应用层面上&#xff0c;干预到多个不同线程代码的执行顺序&#xff0c;此处的干预&a…

Java动态代理机制 代码示例demo

文章目录 JDK动态代理代码实现示例1.定义发送短信的接口2.实现发送短信的接口3.定义一个 JDK 动态代理类4.获取代理对象的工厂类5.实际使用 JDK 动态代理只能代理实现了接口的类CGLIB动态代理代码实现示例1.实现一个使用阿里云发送短信的类2.自定义 MethodInterceptor&#xff…

Java——猫猫图鉴微信小程序(前后端分离版)

目录 一、开源项目 二、项目来源 三、使用框架 四、小程序功能 1、用户功能 2、管理员功能 五、使用docker快速部署 六、更新信息 审核说明 一、开源项目 猫咪信息点-ruoyi-cat: 1、一直想做点项目进行学习与练手&#xff0c;所以做了一个对自己来说可以完成的…

HCIP:rip综合实验

实验要求&#xff1a; 【R1-R2-R3-R4-R5运行RIPV2】 【R6-R7运行RIPV1】 1.使用合理IP地址规划网络&#xff0c;各自创建环回接口 2.R1创建环回 172.16.1.1/24 172.16.2.1/24 172.16.3.1/24 3.要求R3使用R2访问R1环回 4.加快网络收敛&#xff0c;减少路由条目数量&#xff0c;增…

Unity中URP下的添加雾效支持

文章目录 前言一、URP下Shader支持雾效的步骤1、添加雾效变体2、在Varying结构体中添加雾效因子3、在顶点着色器中&#xff0c;我们使用内置函数得到雾效因子4、在片元着色器中&#xff0c;把输出颜色 和 雾效因子混合输出 二、在Unity中打开雾效三、测试代码 前言 我们使用之…

ubuntu20部署Bringing-Old-Photos-Back-to-Life

环境准备&#xff1a; ubuntu20.04 Python 3.8.10 首先将微软的「Bringing-Old-Photos-Back-to-Life」库 clone 到本地&#xff1a; git clone https://github.com/microsoft/Bringing-Old-Photos-Back-to-Life.git cd Face_Enhancement/models/networks/ git clone https:/…

NFC物联网智慧校园解决方案

近场通信(Near Field Communication&#xff0c;NFC)又称近距离无线通信&#xff0c;是一种短距离的高频无线通信技术&#xff0c;允许电子设备之间进行非接触式点对点数据传输交换数据。这个技术由免接触式射频识别(RFID)发展而来&#xff0c;并兼容 RFID&#xff0c;主要用于…

解决VNC连接Ubuntu服务器打开终端出现闪退情况

服务器环境 阿里云ECS服务器 操作系统&#xff1a;Ubuntu 20.0.4 如何使用VNC连接阿里云ECS服务器 1.阿里云官方指导&#xff1a;通过VNC搭建Ubuntu 18.04和20.04图形界面 2.新手入门ECS——ubuntu 20.04安装图形化界面和本地VNC连接 问题描述 使用VNC连接上新申请阿里云服…

github鉴权失败

问题&#xff1a; 如上图所示 git push 时发生了报错&#xff0c;鉴权失败&#xff1b; 解决方案 Settings->Developer settings->Personal access tokens->Generate new token。创建新的访问密钥&#xff0c;勾选repo栏&#xff0c;选择有效期&#xff0c;为密钥命…

鸿蒙HarmonyOS-图表应用

简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在HarmonyOS应用开发中&#xff0c;一个强大而灵活的图表库是实现这一目标的关键。而MPChart就是这样一款图表库&#xff0c;它为开发者提供了丰富的功能和灵活性&#xff0c;使得…

【持续更新ing】uniapp+springboot实现个人备忘录系统【前后端分离】

目录 &#xff08;1&#xff09;项目可行性分析 &#xff08;2&#xff09;需求描述 &#xff08;3&#xff09;界面原型 &#xff08;4&#xff09;数据库设计 &#xff08;5&#xff09;后端工程 接下来我们使用uniappspringboot实现一个简单的前后端分离的小项目----个…

Spark作业的调度与执行流程

Apache Spark是一个分布式计算框架&#xff0c;用于处理大规模数据。了解Spark作业的调度与执行流程是构建高效分布式应用程序的关键。本文将深入探讨Spark作业的组成部分、调度过程以及执行流程&#xff0c;并提供丰富的示例代码来帮助大家更好地理解这些概念。 Spark作业的组…

[Angular] 笔记 16:模板驱动表单 - 选择框与选项

油管视频&#xff1a; Select & Option (Template Driven Forms) Select & Option 在 pokemon.ts 中新增 interface: export interface Pokemon {id: number;name: string;type: string;isCool: boolean;isStylish: boolean;acceptTerms: boolean; }// new interface…

前端图片适配不同屏幕方案

预备知识&#xff1a; 设备独立像素,以下图的iphone12 Pro为例&#xff0c;390*844表示的就是设备独立像素&#xff08;DIP&#xff09;,也可以理解为CSS像素 物理像素&#xff08;设备像素&#xff09;&#xff0c;就是屏幕的分辨率&#xff0c;显示屏就是由一个个物理像素…

QT/C++ 远程数据采集上位机+服务器

一、项目介绍&#xff1a; 远程数据采集与传输 课题要求:编写个基于TCP的网络数据获取与传输的应用程序; 该程序具备以下功能: 1)本地端程序够通过串口与下位机(单片机)进行通信&#xff0c;实现数据采集任务 2)本地端程序能将所获取下位机数据进行保存(如csv文本格式等); 3…