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 {

    @Test
    void 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;

    @BeforeEach
    public void setUp() {
        this.calculator = new Calculator();
    }

    @AfterEach
    public void tearDown() {
        this.calculator = null;
    }

    @Test
    void testAdd() {
        assertEquals(100, this.calculator.add(100));
        assertEquals(150, this.calculator.add(50));
        assertEquals(130, this.calculator.add(-20));
    }

    @Test
    void 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 {

    @Test
    void 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));
    }

    @Test
    void 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;

    @BeforeEach
    public void setUp() {
        this.config = new Config();
    }

    @AfterEach
    public 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.mfbz.cn/a/278589.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

私有部署ELK,搭建自己的日志中心(四)-- kibana展示es的数据

一、说在前面的话 前一篇已把elk的安装连带讲完&#xff0c;本文重在讲述如何在kibana展示es数据。 二、数据的展示 展示es数据库的客户端工具有很多&#xff0c;比如es head插件&#xff0c;但是一说到要查询日志&#xff0c;还是非kibana莫属了。 1、kibana.yml # 服务端…

边缘计算网关:重新定义物联网数据处理

随着物联网&#xff08;IoT&#xff09;设备的爆炸式增长&#xff0c;数据处理和分析的需求也在迅速增加。传统的数据处理方式&#xff0c;将所有数据传输到中心服务器进行处理&#xff0c;不仅增加了网络负担&#xff0c;还可能导致数据延迟和安全问题。因此&#xff0c;边缘计…

求解拍频的信号特征

这张图上&#xff0c;时域已经明显产生调幅波的拍频特征。利用宏观的拍频特征可以肉眼识读两个信号的频差&#xff1a; 一秒是69.42个像素。拍频周期是&#xff1a;21.857像素。所以&#xff0c;拍频的周期是&#xff1a;3.7161Hz. 其中一个频率是50Hz&#xff0c;另一个频率…

ACM32F403/F433 12 位多通道国产芯片,支持 MPU 存储保护功能,应用于工业控制,智能家居等产品中

ACM32F403/F433 芯片的内核基于 ARMv8-M 架构&#xff0c;支持 Cortex-M33 和 Cortex-M4F 指令集。芯片内核 支持一整套DSP指令用于数字信号处理&#xff0c;支持单精度FPU处理浮点数据&#xff0c;同时还支持Memory Protection Unit &#xff08;MPU&#xff09;用于提升应用的…

【数据结构】七、图

一、概念 图&#xff1a;记为G(V,E) 有向图&#xff1a;每条边都有方向 无向图&#xff1a;边无方向 完全图&#xff1a;每个顶点都与剩下的所有顶点相连 完全有向图有n(n-1)条边&#xff1b;完全无向图有n(n-1)/2条边 带权图&#xff1a;边上标有数值的图 连通图&#…

OpenAI: InstructGPT的简介

OpenAI: InstructGPT paper: 2022.3 Training Language Model to follow instructions with human feedback Model: (1.3B, 6B, 175B) GPT3 一言以蔽之&#xff1a;你们还在刷Benchamrk?我们已经换玩法了&#xff01;更好的AI才是目标 这里把InstructGPT拆成两个部分&#…

【JavaWeb】day01-HTMLCSS

day01-HTML&CSS HTML 图片标签&#xff1a;<img> src&#xff1a;指定图像URL&#xff08;绝对路径/相对路径&#xff09;width&#xff1a;图像宽度&#xff08;像素/相对于父元素的百分比&#xff09;height&#xff1a;图像高度&#xff08;像素/相对于父元素的百…

STM32CubeMX教程10 RTC 实时时钟 - 周期唤醒、闹钟A/B事件和备份寄存器

目录 1、准备材料 2、实验目标 3、实验流程 3.0、前提知识 3.1、CubeMX相关配置 3.1.1 、时钟树配置 3.1.2、外设参数配置 3.1.3 、外设中断配置 3.2、生成代码 3.2.1、外设初始化函数调用流程 3.2.2、外设中断函数调用流程 3.2.3、添加其他必要代码 4、常用函数 …

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 查看当前集群所有的命…

【C语言数组传参】规则详解

目录 数组传参介绍 数组传参规则 数组传参的实参 特殊情况一&#xff1a;sizeof&#xff08;数组名&#xff09; 特殊情况二&#xff1a;&数组名 数组传参的形参 数组传参使用数组名作为形参接收 形参如果是⼀维数组 形参如果是⼆维数组 数组传参使用指针作为形参…

Python 实现 PDF 到 Word 文档的高效转换(DOC、DOCX)

PDF&#xff08;Portable Document Format&#xff09;已成为一种广泛使用的电子文档格式。PDF的主要优势是跨平台&#xff0c;可以在不同设备上呈现一致的外观。然而&#xff0c;当我们需要对文件内容进行编辑或修改&#xff0c;直接编辑PDF文件会非常困难&#xff0c;而且效果…

万界星空科技车间生产管理系统解决方案

车间管理系统解决方案:   &#xff08;一&#xff09;车间生产计划管理解决方案   车间管理系统解决方案对于一般的生产计划&#xff0c;需完成编制、审批、下达、执行、完工等操作&#xff0c;车间管理系统解决方案立足于减少中间环节浪费&#xff0c;节约成本&#xff0c…

Ubuntu22.04系统安装软件、显卡驱动、cuda、cudnn、pytorch

Ubuntu22.04系统安装软件、显卡驱动、cuda、cudnn、pytorch 安装 Nvidia 显卡驱动安装 CUDA安装 cuDNN安装 VSCode安装 Anaconda 并更换源在虚拟环境中安装 GPU 版本的 PyTorchReference 这篇博文主要介绍的是 Ubuntu22.04 系统中软件、显卡驱动、cuda、cudnn、pytorch 等软件和…

uniapp+echarts开发APP版本教程

需求 需要在uniappecharts展示图表功能&#xff0c;是APP版本&#xff0c;不是小程序。找了好多教程都乱七八糟的&#xff0c;无法实现。以下是效果图 教程 1、安装插件 HBuilder安装echarts插件&#xff0c;插件地址如下。安装完成后在uni_modules/lime-echart文件夹下 ht…

7.6分割回文串(LC131-M)

算法&#xff1a; 有很多分割结果&#xff0c;按照for循环去做肯定做不来 这个时候就要想到回溯&#xff01;那就要画树&#xff01; 画树 分割的画树过程其实和组合很像。 例如对于字符串aab&#xff1a; 组合问题&#xff1a;选取一个a之后&#xff0c;在ab中再去选取第…

彻底理解前端安全面试题(1)—— XSS 攻击,3种XSS攻击详解,建议收藏(含源码)

前言 前端关于网络安全看似高深莫测&#xff0c;其实来来回回就那么点东西&#xff0c;我总结一下就是 3 1 4&#xff0c;3个用字母描述的【分别是 XSS、CSRF、CORS】 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略&#xff0c;其他的都是网络攻击。除了这…

【深度学习-图像分类】02 - AlexNet 论文学习与总结

论文地址&#xff1a;ImageNet Classification with Deep Convolutional Neural Networks 论文学习 1. 摘要 本研究训练了一个大型深度卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用于对ImageNet LSVRC-2010比赛中的1.2百万高分辨率图像进行分类&#xff0c;这些图…

nginx设置跨域访问

目录 一&#xff1a;前端请求 二&#xff1a;后端设置 网站架构前端使用jquery请求&#xff0c;后端使用nginxphp-fpm 一&#xff1a;前端请求 <script> $.getJSON(http://nngzh.youjoy.com/cc.php, { openid: sd, }, function(res) { alert(res); if(res.code 0) …

GLTF 编辑器实现逼真3D动物毛发效果

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 要实现逼真的3D动物毛发效果&#xff0c;可以采用以下技术和方法&…

【51单片机系列】DS1302时钟模块扩展实验之与EEPROM结合使用只进行一次初始化工作

本文是关于时钟芯片DS1302的扩展实验。 文章目录 一、实验分析二、proteus仿真原理图三、软件设计及结果 本实验实现的目的&#xff1a;利用AT24C02掉电不丢失的功能&#xff0c;存储数据用来辨别DS1302时钟是否已经初始化&#xff0c;如果初始化就不执行DS1302初始化函数。 一…