• 【Java】[junit] (一)Java 测试入门 ,junit的基本操作 ,@Test等注解的用法


    Java Testing

    本文带你入门junit和mockito

    junit

    环境和前置知识

    这里我用的是IDEA 、jdk11

    需要以下基础:

    • java (类、静态函数)
    • maven (知道怎么用pom.xml添加依赖)
    • IDEA(基础操作)

    新建一个项目

    在这里插入图片描述

    导入maven依赖

    打开pom.xml 添加junit的几行依赖内容。
    在这里插入图片描述

    
       
                org.junit.jupiter
                junit-jupiter
                RELEASE
                test
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码结构

    在这里插入图片描述

    现在的idea都会自动生成标准的项目结构,main文件夹里的java文件夹放程序文件,test内的java文件夹则明显就是存放我们测试代码的地方。
    通常,单元测试是在单独的源文件夹中创建的,以使测试代码与真实代码分开。Maven 和 Gradle 构建工具的标准约定是:

    • src/main/java - 用于 Java 类
    • src/test/java - 用于测试类

    编写一个待测试的demo

    我们写个简单的计算器,模拟实际开发中的一些常见的开发问题,并进行测试。
    在这里插入图片描述

    我们编写了如下代码:

    /**
     * @author gongfpp  https://github.com/gongfpp
     * @date 2022/8/26 9:44
     */
    public class Calculator {
    
        private int value;
    
        public static int add(int a,int b){
            return a+b;
        }
    
        public static int sub(int a,int b){
            return a+b;
        }
    
        public static void main(String[] args) {
            System.out.println("yes");
        }
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里,我开发代码时复制黏贴不小心把减法(sub)的代码ctrl +v 粘了个加法的进去(假装),但是由于只是一个符号的区别,我没有看出来(假装我是瞎子,但实际开发中代码复杂的时候确实非常难看出来,有时候浪费一天结果发现是很低级的错误,有经历过的都懂)
    ,接下来我们进行测试

    编写测试代码

    我们很容易想到在main函数里调用编写的代码进行测试,但程序并非一成不变的,如果每次加新功能测试的时候,main函数内每次都注释掉原有的代码而添加测试代码,测完了再删测试代码并还原注释,一是非常麻烦,二是非常臃肿,三是不规范。于是我们需要一些测试框架来辅助我们进行单元测试,单元测试指的是能对能测试的最小单元(unit)进行测试,一般是一个方法。
    在这里插入图片描述

    我们在test/java/内新建一个CalculatorTest类
    Import我们需要的test注解,并写一个没有任何执行内容的方法,在它上面添加@Test注解。

    /**
     * @author gongfpp  https://github.com/gongfpp
     * @date 2022/8/26 9:55
     */
    import org.junit.jupiter.api.Test;
    public class CalculatorTest {
        @Test
        public void test(){
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这时这个方法可以被作为独立单元来进行测试,左边能看到绿色的运行。这样我们免去了每次都运行main方法的繁杂,而且每个@Test方法都能独立运行。
    运行结果如下:
    在这里插入图片描述

    这里由于什么都没写,便只会有测试通过的结果。
    太棒了,不写测试代码就不会通不过测试!(别)

    为了更多的测试功能,我们import一些静态函数

    import static org.junit.jupiter.api.Assertions.*;
    
    • 1

    import static 的意思是导入后面的包内的类的静态函数,这样我们使用的时候就不需要类名。
    不然我们调用的时候需要Assertions.assertEquals(); 这样比较长,也没必要,测试类里一般只有测试方法,没有重名的风险。

    import org.junit.jupiter.api.Test;
    import static org.junit.jupiter.api.Assertions.*;
    public class CalculatorTest {
        @Test
        public void add5_5_10(){
            assertEquals(10,Calculator.add(5,5));
        }
        
        @Test
        public void sub10_5_5(){
            assertEquals(5,Calculator.sub(10,5));
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    函数名建议使用一眼能看出来的含义,这里我们测试两个用例(case),assertEquals()的参数分别为期望值和实际值,当两个相同则测试通过,不同则失败。
    在这里插入图片描述

    我们点击类旁的run则可以运行所有带@Test的测试用例。运行结果如下。
    在这里插入图片描述

    明确指出期望值和实际值,这样我们就能去修bug了。

    同理,常用的测试函数如下 ,可以在注释里看函数作用:

    /**
     * @author gongfpp  https://github.com/gongfpp
     * @date 2022/8/26 9:55
     */
    import org.junit.jupiter.api.*;
    
    
    import java.time.Duration;
    
    import static org.junit.jupiter.api.Assertions.*;
    import static org.junit.jupiter.api.Assumptions.*;
    
    public class CalculatorTest {
        @Test
        public void add5_5_10(){
            assertEquals(10,Calculator.add(5,5));
        }
    
        @Test
        public void sub10_5_5(){
            assertEquals(5,Calculator.sub(10,5));
        }
    
    
        @Test
        public void testTrueWithTrue(){
            //某个结果必须为true,否则测试失败 这里成功
            assertTrue(true);
        }
    
        @Test
        @DisplayName("我的名字会代替函数名出现在测试运行窗口,你跑我一下试试")
        public void tetsTrueWithFalse(){
            //某个结果必须为true,否则测试失败 这里失败
            assertTrue(false);
        }
    
        @Test
        public void testThrow(){
            //运行不抛出异常,这里一般用lambda函数,在lambda内写逻辑代码,lambda固定格式 ()->{} ,这里只需要知道代码写在大括号里就行了。
            assertDoesNotThrow(()->{
                throw new Exception("AAA");
            });
        }
    
    
        @Test
        public void testTimeout1Sec(){
    //        限制时间未完成执行则测试不通过,第一个函数为Duration.ofxxx ,可选秒、分钟、小时等,
            assertTimeout(Duration.ofSeconds(1),()->{
                //线程休眠4秒,这里时间限制是1秒,所以肯定运行超时,测试不通过
                Thread.sleep(4000);
            });
        }
    
        @BeforeEach
        public void beforeEach(){
    //        BeforeEach一般是每个方法前的初始化,比如Calculator calculator = new Calculator() 这样的代码,
    //        每次都要写一遍很麻烦,所以有了这个,可以理解为这里的代码会被复制黏贴到每个test函数的开头部分,不能是static
            System.out.println("每个运行方法前我出来一次  我不能是静态函数");
        }
    
        @BeforeAll
        public static void beforeAll(){
    //        beforeAll一般是所以方法执行前的一次操作,比如LogSave("开始测试calculor类"),这样的代码,一批测试只运行一次,
    //        必须是static,可以理解为先执行这里的代码,再去分别运行其他的@Test代码
            System.out.println("执行所有测试前我来一次 我必须是静态函数");
        }
    
    
        //可以代替@Test 并且跑3次,参数为运行次数
        @RepeatedTest(3)
        public void other(){
    //        当参数条件为true才往下运行,否则忽略该测试
    //        比如先跑一个条件方法,当满足才往下继续
            assumeTrue(false);
    
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
  • 相关阅读:
    linux查找命令使用的正则表达式
    深入了解面向对象——面向对象的重要特征(C#)未写完
    记录自签tomcat所用TLS1.2链接所需SSL证书
    Ubuntu 22.04 | 20.04 |18.04 上安装 PHP 8.1
    Nacos源码 (6) Grpc概述与Nacos集成
    微信小程序之点击事件
    语音信号处理(二): 发声生理、听觉生理与听觉心理
    Kong网关命令详解
    Buuctf [MRCTF2020]Ez_bypass 1 WP解析
    GPT接入飞书
  • 原文地址:https://blog.csdn.net/gongfpp/article/details/126540432