【实际开发01】- 单元测试 ( 追求正确性 )

news2024/12/23 11:43:25

目录

0. 单元测试 概念 / 解析

1. 为什么要进行单元测试

1. JUnit ~ @Test

2. IDEA 中使用 junit 单元测试 , 不能使用 Scanner 的解决方法

3. Junit 测试 Tutorial

1. daiding

4. @Test 修饰的方法必须 public

1. validatePublicVoidNoArgMethods(Test.class, false, errors);

2. public static void main(String[] args) {} ~ 程序入口

1. main 概念 / 解析

1. 为什么 main 方法是静态的(static)

2. 为什么main 方法是公有的 ( public )

3. 为什么 main 方法没有返回值 ( void )

2. 使用 main() 方法来测试有很多坏处

3. String[] 字符串数组

3. Junit 单元测试 和 main 函数区别 ( 踩坑 )

1. Junit 单元测试 不支持 多线程

1. Junit

2. main 函数

3. 解决方案

2. 结论 : 尽量不要在 @test 开启新线程


0. 单元测试 概念 / 解析

单元测试 , 就是针对最小的功能单元编写测试代码

在 Java 中 , 最小的功能单元就是方法 , 因此 , 对 Java 程序员进行单元测试实际上就是对 Java 方法的测试。

单元测试 : 任何一个小模块、小功能;模块式测试

 1、可以减少出错、缩小调试影响面
 ​
 2、一步步测 , 才是最快的方法;
 ​
 3、完成一部分测试一部分 , 防止自己懵逼!

写完一节 , 就进行单元测试 ;避免追求一气呵成的错误集中情况! (单元测试包 , 需保证唯一)


1. 为什么要进行单元测试

因为单元测试可以确保你编写的代码是符合软件需求和遵循开发规范的。

单元测试是所有测试中最底层的一类测试 , 是第一个环节 , 也是最重要的一个环节 , 是唯一一次能够达到代码覆盖率 100% 的测试 , 是整个软件测试过程的基础和前提。

可以这么说 , 单元测试的性价比是最好的。

微软公司之前有这样一个统计:

bug 在单元测试阶段被发现的平均耗时是 3.25 小时 , 如果遗漏到系统测试则需要 11.5 个小时。

经我这么一说 , 你应该已经很清楚单元测试的重要性了。

那在你最初编写测试代码的时候 , 是不是经常这么做?就像下面这样。


1. JUnit ~ @Test

IDEA 会自动在当前类所在的包下生成一个类名带 Test ( 惯例 ) 的测试类


2. IDEA 中使用 junit 单元测试 , 不能使用 Scanner 的解决方法

参考:

解决IDEA中使用junit单元测试不能使用Scanner的方法_花開彼岸天丶的博客-CSDN博客_junit不能接收sacanner 解决IDEA中使用junit单元测试不能使用Scanner的方法

编程时在 IDEA 中引入单元测试 , 并在里面用了 Scanner 时 , 运行时会出一直在跑的问题 :

方案1 : 将测试类的代码放入 main 函数运行

方案2 : 在 IDEA 中点击 help -> Edit Custom Vm Options… , 进入 , 在最后一行加入:-Deditable.java.test.console=true

最后 : 在 eclipse 中则不会出现这个问题;


3. Junit 测试 Tutorial


1. daiding


4. @Test 修饰的方法必须 public


1. validatePublicVoidNoArgMethods(Test.class, false, errors);

查阅 Junit 源码 :

     protected void validateInstanceMethods(List<Throwable> errors) {
         
         validatePublicVoidNoArgMethods(After.class, false, errors);
         validatePublicVoidNoArgMethods(Before.class, false, errors);
         
         validateTestMethods(errors);
         if (computeTestMethods().size() == 0)
             errors.add(new Exception(" No runnable methods "));
     }
 ​
     protected void validateTestMethods(List<Throwable> errors) {
         validatePublicVoidNoArgMethods(Test.class, false, errors);
     }

这表明 @Before、@After、@Test 注解的方法必须是 : public,void,非静态,不带参数。


2. public static void main(String[] args) {} ~ 程序入口

Main 方法是 Java 程序的入口

记住,我们这里不会讨论 Servlet、MIDlet 和其他任何容器管理的 java 程序,在 java 核心编程中,JVM 会查找类中的 public static void main(String[]args),如果找不到该方法就抛出错误 NoSuchMethodError:main 程序终止。

Main 方法必须严格遵循它的语法规则,方法签名必须是 public static void,参数是字符串数组类型,如果是 Java1.5 及以后的版本还可以使用可变参数:

public static void main(String... args)

今天终于搞懂了:为什么 Java 的 main 方法必须是 public static void?

Public:访问权限最大。

static:不需要对象,直接类名即可。

void:主函数没有返回值。

Main:主函数特定的名称。

(String[] args):主函数的参数,是一个字符串数组类型的参数,jvm 调用 main() 方法时,传递的实际参数是 new String[0]。

 jvm 默认传递的是长度为0的字符串数组,
 我们在运行该类时,也可以指定具体的参数进行传递。
 可以在控制台,运行该类时,在后面加入参数。参数之间通过空格隔开。jvm会自动将这些字符串参数作为args数组中的元素,进行存储。


1. main 概念 / 解析

如果需要用 java 命令直接运行一个 Java 类 , 这个 Java 类必须包含 main 方法 ,

这个 main 方法必须使用 public 和 static 来修饰 , 必须使用 void 声明该方法的返回值 ,

而且该方法的参数类型只能是一个字符串数组 , 而不能是其他形式的参数。

对于这个 main 方法而言 , 前面的 public 和 static 修饰符的位置可以互换 , 但其他部分则是固定的。

定义 main 方法时 , 不要写成 Main 方法 , 如果不小心把方法名的首字母写成了大写 , 编译时不会出现任何问题 , 但运行该程序时将给出如图 2 的错误提示:

这个错误提示找不到 main 方法 , 因为 Java 虚拟机只会选择从 main 方法开始执行。

对于 Main 方法 , Java 虚拟机会把该方法当成一个普通方法 , 而不是程序的入口。

main 方法里可以放置程序员需要执行的可执行性语句 , 例如 System.out.println("Hello Java!") ,

这行语句是 Java 里的输出语句 , 用于向控制台输岀“Hello Java!”这个字符串内容 , 输出结束后还输出一个换行符。

在 Java 程序里执行输岀有两种简单的方式:

System.out.print(需要输出的内容) 和 System.out.println (需要输出的内容) , 其中前者在输出结束后不会换行 , 而后者在输出结束后会换行。

总结:

1、main 方法必须声明为 public、static、void,否则 JVM 没法运行程序 。

2、如果 JVM 找不到 main 方法就抛出 NoSuchMethodError:main 异常,

 例如:如果你运行命令:java HelloWrold,JVM 就会在 HelloWorld.class 文件中搜索 public static void main (String[] args) 方法。

3、main 方式是程序的入口,程序执行的开始处。

4、main 方法被一个特定的线程 ”main” 运行,程序会一直运行直到 main 线程结束或者 non-daemon 线程终止。

5、当你看到 “Exception in Thread main” 如:Excpetion in Thread main:Java.lang.NullPointedException,意味着异常来自于 main 线程。

6、你可以声明 main 方法使用 java1.5 的可变参数的方式 ; 如:publicstaticvoid main(String... args)。

7、除了 static、void、和 public,你可以使用 final,synchronized、和 strictfp 修饰符在 main 方法的签名中,如:public strict fp final synchronized static void main(String[] args)

8、main 方法在 Java 可以像其他方法一样被重载,但是 JVM 只会调用上面这种签名规范的 main 方法。

9、你可以使用 throws 子句在方法签名中,可以抛出任何 checked 和 unchecked 异常。

10、静态初始化块在 JVM 调用 main 方法前被执行,它们在类被 JVM 加载到内存的时候就被执行了。


1. 为什么 main 方法是静态的(static)

1、正因为 main 方法是静态的,JVM 调用这个方法就不需要创建任何包含这个 main 方法的实例。

2、因为 C 和 C++ 同样有类似的 main 方法作为程序执行的入口。

3、如果 main 方法不声明为静态的,JVM 就必须创建 main 类的实例,因为构造器可以被重载,JVM 就没法确定调用哪个 main 方法。

4、静态方法和静态数据加载到内存就可以直接调用 , 而不需要像实例方法一样创建实例后才能调用,如果 main 方法是静态的,那么它就会被加载到 JVM 上下文中成为可执行的方法。


2. 为什么main 方法是公有的 ( public )

Java 指定了一些可访问的修饰符 ;如:private、protected、public,任何方法或变量都可以声明为 public,Java 可以从该类之外的地方访问。

因为 main 方法是公共的,JVM 就可以轻松的访问执行它。


3. 为什么 main 方法没有返回值 ( void )

因为 main 返回任何值对程序都没任何意义,所以设计成 void,意味着 main 不会有任何值返回。


2. 使用 main() 方法来测试有很多坏处

1、测试代码没有和源代码分开。

2、不够灵活 , 很难编写一组通用的测试代码。

3、无法自动打印出预期和实际的结果 , 没办法比对。

JUnit 的话 , 就不会再有这种困扰了。

我可以非常简单地组织测试代码 , 并随时运行它们 , 还能给出准确的测试报告 , 让你在最短的时间内发现自己编写的代码到底哪里出了问题。


3. String[] 字符串数组


3. Junit 单元测试 和 main 函数区别 ( 踩坑 )


1. Junit 单元测试 不支持 多线程

当 Thread 了新的线程后 , Junit 单元测试 在主线程运行结束后就关闭了 , 而不会等子线程运行结束。

而 main 函数就不存在这个问题了...

测试对比如下:


1. Junit

书写一个定时任务 , 每500ms执行一次:

运行结果:

可以看出 , 当主线程执行结束后 , 就关闭了 , 不会等 子线程运行


2. main 函数

同上 , 书写一个定时任务 , 每 500ms 执行一次:

运行结果如下:  


3. 解决方案

如果想使用Junit 进行多线程测试 , 可以先睡眠主线程 , 例如:

    @Test
    public void test(){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+ ": ==========Junit 定时任务 =========");
            }
        } ,  new Date() ,  500);

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName()+ "==========Junit 主线程任务=========");
    }


2. 结论 : 尽量不要在 @test 开启新线程

@Test 单测方法和 main 方法

 在做一个多线程测试的时候发现的一个比较好玩的问题 , 
     在@Test的单测方法中开启了两个线程 , 本来应该在B()方法中的打印 , 没打出来 , 
     看了一下单测方法的线程是Thread[main , 5 , main] , 这方法开启的是main线程。
 ​
 网上一些人的观点是单测方法结束的时候会把里面的资源释放了 , 导致里面线程提前结束。
public class 多线程测试01 {
    int a ;
    boolean flag ;


    public static void main(String[] agrs) {
        多线程测试01 shen = new 多线程测试01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                shen.A();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                    shen.B();
            }
        }).start();
    }

    // @Test 单测方法有一个问题 , 当单测方法结束的时候里面的线程也要结束 , 不管是不是执行完成
    // 结论不要在@Test开启线程
    @Test
    public void play() {
        多线程测试01 shen = new 多线程测试01();
        new Thread(new Runnable() {
            @Override
            public void run() {
                shen.A();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                shen.B();
            }
        }).start();

        System.out.println(Thread.currentThread());

    }


    public void A() {
//        try {
//            Thread.sleep(100);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        a = 1;
        flag = true;
    }


    public void B()  {
        if (flag) {
            System.out.println("flag = true  " + a);
        } else if(!flag){
            System.out.println("falg = false  " + a);
        }
    }
}

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

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

相关文章

功率二极管的损耗分析和选型原则

功率二极管的损耗分析和选型原则 tip&#xff1a;参考网上资料&#xff0c;学习为主 1.二极管的分类 2.二极管的损耗组成 3.二级管的损耗分析 4.应用实例1.Flyback电源电路二极管损耗计算 5.实例应用2.BOOST电路二极管损耗计算 6.实例应用3.大功率整流桥二极管参数计算 7.选型…

sqli-labs 5~6 多命通关攻略

sqli-labs 5~6 多命通关攻略描述判断注入类型正常输入不正常输入错误输入判断 SQL 查询结果的列数猜测 SQL 查询结果中的列数为两列猜测 SQL 查询结果中的列数为三列猜测 SQL 查询结果中的列数为四列爆破方式的可行性函数 UpdateXML()爆破&#xff08;报错注入&#xff09;爆破…

农业智能化进入“刚需时代 ” ,维视智造机器视觉实验室赋能新农科人才培养

1、传统农业数字化转型 新农科人才急需紧缺数千年来&#xff0c;农业是我国立国基础&#xff0c;农业兴衰关系到国家的命运。在大力推动乡村振兴的背景下&#xff0c;高校作为强农兴农的“国之重器”&#xff0c;在培育“农”的传人、新农科建设方面扮演着不可替代的角色。世界…

C++入门——内联函数、extern “C“

一. 内联函数 1.概念及分析 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调 用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 int Add(int a, int b) {int c a b;return c; }int main() {int re…

聚焦技术创新实力,时序数据库 TDengine 荣登中国技术先锋年度评选两大榜单

2023 年 1 月 5 日&#xff0c;中国技术先锋年度评选 | 2022 中国最受开发者欢迎的技术活动榜单正式发布。作为中国领先的新一代开发者社区&#xff0c;SegmentFault 思否依托社区活动板块及全站数百万开发者用户行为数据&#xff0c;及活动规模、内容好评度、行业综合影响力指…

Go语言设计与实现 --调度器(详细介绍)

GMP和GM模型 先来一张图&#xff1a; G(Goroutine)&#xff1a;代表Go 协程Goroutine&#xff0c;存储了 Goroutine 的执行栈信息、Goroutine 状态以及 Goroutine 的任务函数等。G的数量无限制&#xff0c;理论上只受内存的影响&#xff0c;创建一个 G 的初始栈大小为2-4K&…

vue项目安装使用element_UI

安装element_UI之前需要安装VUE脚手架框架! 第一步: 在Vscode 随意打开一个文件夹,在集成终端打开 npm i -g vue/cli (检测: vue -V) 第二步:新建一个文件夹,并且在集成终端打开安装VUE脚手架 需要输入命令: vue create yan6 //yan6 为自定义文件名 1: 选第三个自定义 2: 将…

SpringBoot缓存数据(官方案例)

在线文档项目结构 1.源码克隆&#xff1a;git clone https://github.com/spring-guides/gs-caching.git 2.包含两个项目initial和complete&#xff0c;initial可以根据文档练习完善&#xff0c;complete是完整项目 3.功能描述&#xff1a;构建应用程序&#xff0c;在图书存储库…

JAVA并发编程工具篇--1理解线程池任务的执行和线程的销毁

前言&#xff1a;在编程中我们为什么要使用线程池&#xff0c;线程池中的线程是怎么执行任务的&#xff0c;线程池中的线程是如何复用和销毁的&#xff1b; 1 什么是线程池&#xff1a; 提前创建一些线程放到一个地方&#xff0c;使用的时候直接获取&#xff0c;避免频繁的创建…

CalDAV网页客户端AgenDAV

什么是 AgenDAV &#xff1f; AgenDAV 是一个类似于 Google 日历的 CalDAV 网络客户端&#xff0c;具有 AJAX 界面&#xff0c;允许用户管理自己的日历和共享的日历。 注意事项 AgenDAV依赖于 CalDAV 服务器&#xff08;Bakal、DAViCal 等&#xff09;&#xff0c;所以需要先安…

软件测试员在面试中常遇问题

目前&#xff0c;疫情已经逐渐得到了控制&#xff0c;各行各业都掀起了复工大潮。与此同时&#xff0c;软件测试的招聘需求也随着复工的开始而变得紧急起来&#xff0c;而求职者应该怎样抓住机会进行应聘呢&#xff1f;首先最重要的就是多刷面试题&#xff0c;这样才能才面试过…

CSS权威指南(五)字体

文章目录1.字体族2.font-face3.字重&#xff08;font-weight&#xff09;4.字号&#xff08;font-size&#xff09;5.字形&#xff08;font-style&#xff09;6.字体拉伸&#xff08;font-stretch&#xff09;7.字距&#xff08;font-kerning&#xff09;8.字体变形&#xff08…

Python 办公自动化,全网最全整理来了!拒绝无效率加班!

大家好&#xff0c;今天给大家分享一篇 Python 自动化办公干货&#xff0c;整整42个实战项目案例。每一个项目案例都有详细的视频讲解&#xff0c;是一套非常全面的Python自动化办公项目&#xff0c;建议大家收藏后学习&#xff0c;梳理不易&#xff0c;记得点赞支持。详细目录…

【菜菜的CV进阶之路 - 深度学习环境搭建】常用软件安装

四、安装网易云 双系统装完了&#xff0c;下一步当然是&#xff0c;休息一下&#xff0c;听一首歌啦~ 1、连网&#xff1a;只能使用wifi连&#xff0c;网线直连的话&#xff0c;还需要配置 2、安装网易云&#xff1a; 下载最新的Linux安装包&#xff0c;然后 sudo apt inst…

数据的存储(C语言)

数据类型&#xff1a; 要了解数据是如何存储的&#xff0c;我们就得先知道C语言中的数据类型 基本数据类型 基本数据类型&#xff0c;也就是C语言内置类型&#xff1a; char -> 字符型 short -> 短整型 int -> 整…

html textarea 插入字符在光标处

textarea 插入字符在光标处前言深度解析1 效果图上代码前言 深度解析 1 效果图 上代码 <!DOCUMENT><html><head> <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css&qu…

Semantic Segmentation | 评价指标代码解析

如有错误&#xff0c;恳请指出。 文章目录1. 定义解析2. 代码解析之前有记录过关于图像语义分割的相关评价指标与经典网络&#xff0c;在看PointNet的语义分割训练脚本的时候&#xff0c;图像的语义分割和点云的语义分割其实本质上是一致的。所以这里想记录一下语义分割的评价指…

MySQL下载及使用navicat连接mysql数据库(含下载地址、超具体细节、推荐数据库教程)

目录下载地址安装流程第一步&#xff1a;开始安装第二步&#xff1a;类型选择第三步&#xff1a;developer default第四步&#xff1a;execute第五步&#xff1a;服务器配置窗口第六步&#xff1a;网络类型配置窗口第七步&#xff1a;第八步&#xff1a;服务器密码设置窗口第九…

Vue全家桶 Pinia状态管理

Pinia状态管理1. Pinia和Vuex的对比2. 创建Pinia的Store3. Store 简介与使用4. Pinia核心概念State5. Pinia核心概念Getters6. Pinia核心概念ActionsPinia开始于大概2019年&#xff0c;最初是作为一个实验为Vue重新设计状态管理&#xff0c;让它用起来像组合式API&#xff0c;从…

[C语言]初步的来了解一下指针(多图详解)

目录 1.指针是什么 2.指针类型 2.1指针类型的意义(-整数) 2.2指针的解引用 3.野指针 3.1野指针出现的情况 3.2 如何规避野指针 4.指针运算 4.1指针-整数 4.2指针-(减)指针 5.二级指针 1.指针是什么 指针是内存中最小的单元编号&#xff0c;也就是地址。指针还可以是一种…