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

【JUnit实战3_01】第一章:JUnit 起步

文章目录

  • 第一章 JUnit 起步
    • 1.1 开发者的分类
    • 1.2 JUnit 的历史
    • 1.3 与单元测试相关的基本概念
    • 1.4 从 add 方法开始
    • 1.5 测试框架必须具备的三个目标
    • 1.6 JUnit 的入门设置
    • 1.7 第一个 JUnit 单元测试

写在前面
没想到今年还会再开一个关于测试的新专题,也算圆了很久以来的一个夙愿吧。在 AI 浪潮的席卷之下,软件质量和安全保障也被更多人重视起来,面对越来越像初级程序员的 AI 助手和智能体,与其天天苦思冥想如何看待当前的软件测试水平和评价体系这类漫无边际的宏大话题,不如静下心来好好学一下软件测试的相关理论和 JUnit 这样的单元测试框架来得实在。

第一章 JUnit 起步

本章快速介绍测试的基本概念,同时也是本书必备的入门知识。

Never in the field of software development was so much owed by so many to so few lines of code.
在软件开发领域,还从未有如此少的代码量能对如此多的人产生如此重大的影响。

—— Martin Fowler

1.1 开发者的分类

基于是否熟练掌握测试技能,可将开发者大致分类两类——

  • 纯手动测试型(“play-test” developer)
  • 测试爱好者型(the test-infected)

1.2 JUnit 的历史

1997 年,Erich GammaKent Beck 合作开发了 JUnit。当时 Erich 希望 Kent 尝试 Java,并对 Kent 早年间为 Smalltalk 设计的 SUnit 测试框架充满兴趣。Erich 是设计模式“四人帮”(GOF)成员之一,而 Kent 则因开创了 极限编程 而享誉业内。

JUnit 之于 Java 单元测试,相当于 MS Excel 之于办公软件,都是各自领域内的事实标准。

JUnit 是托管到 GitHub 的开源软件,基于 Eclipse 公共许可(Eclipse Public License)。其底层测试模型 xUnit 正逐步成为其它多种语言的标准框架,如 ASPC++C#EiffelDelphiPerlPHPPythonRebolSmalltalk 以及 Visual Basic

1.3 与单元测试相关的基本概念

本书中 单元测试 的含义界定(更狭义):检验独立工作单元行为的测试(也称为 开发者测试),即确认某方法能接受预期范围的输入,并针对每个输入返回预期的结果。
这里的 工作单元,应该是不直接依赖其他任务完成情况的某类任务,这在 Java 应用中通常表现为单个方法。

单元测试通常关注的是验证方法是否遵循其 API 契约 的条款
这里的 API 契约,是将应用程序接口(即 API)视为调用方与被调用方之间正式协议的一种观点,其概念源于 Eiffel 兴起的契约式设计实践(Design by Contract)。
单元测试通过 展示预期行为 来定义 API 契约。

单元测试的核心原则:没有自动化测试的功能特性等同于不存在该特性(Any program feature without an automated test simply doesn’t exist.)。

1.4 从 add 方法开始

以单元测试领域的 Hello World 开始:

public class Calculator {public double add(double number1, double number2) {return number1 + number2;}
}

最简单的测试逻辑也最直观:

public class CalculatorTest {public static void main(String[] args) {Calculator calculator = new Calculator();double result = calculator.add(10, 50);if (result != 60) {System.out.println("Bad result: " + result);}}
}

缺陷:测试是否通过还得仔细阅读输出结果,对比脑海中的正确结果,本质上还是手动测试

要体现某测试不通过,最好是以抛异常的方式进行描述。一个更好的测试用例应该通过 模块化 的设计来捕获、处理异常:

public class CalculatorTest {private int nbErrors = 0;public void testAdd() {Calculator calculator = new Calculator();double result = calculator.add(10, 50);if (result != 60) {throw new IllegalStateException("Bad result: " + result);}}public static void main(String[] args) {CalculatorTest test = new CalculatorTest();try {test.testAdd();}catch (Throwable e) { 2test.nbErrors++;e.printStackTrace();}if (test.nbErrors > 0) {throw new IllegalStateException("There were " + test.nbErrors + " error(s)");}}
}

这里的 testAdd() 方法就是一个模块。

1.5 测试框架必须具备的三个目标

  1. 帮助人们写出有效测试;
  2. 写出的测试可以保值(不会很快过气);
  3. 必须能通过代码复用降低编写成本。

1.6 JUnit 的入门设置

JUnit 5 高度依赖注解,让基类去检测所有测试类上的测试方法,对形如 testXYZ 型的方法名执行统一的测试。

本书使用 MavenJUnit 框架的相关依赖进行管理。最开始需要的两个依赖为 junit-jupiter-apijunit-jupiter-engine

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.6.0</version><scope>test</scope>
</dependency>
<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.6.0</version><scope>test</scope>
</dependency>

为了能从命令行运行测试,还需要配置 Maven 插件 maven-surefire-plugin

<build><plugins><plugin><artifactId>maven-surefire-plugin</artifactId><version>2.22.2</version></plugin></plugins>
</build>

另外 Java 版本不得低于 Java 8。由于我本地实测用的 Java 11pom.xml 中还需要手动指定示例项目的 Java 编译版本:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>11</source><target>11</target></configuration>
</plugin>

由于示例源码已根据章节划分为不同的项目,在 IDEA 中直接以章节文件夹为根目录打开项目即可。

1.7 第一个 JUnit 单元测试

先上代码:

package com.manning.junitbook.ch01;import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;public class CalculatorTest {@Testpublic void testAdd() {Calculator calculator = new Calculator();double result = calculator.add(10, 50);assertEquals(60, result, 0);}
}

重要补充:这里的断言方法 assertEquals() 支持三个参数:期望值、实际值、最大误差。具体签名如下:

/*** <em>Assert</em> that {@code expected} and {@code actual} are equal within the given non-negative {@code delta}.* <p>Equality imposed by this method is consistent with {@link Double#equals(Object)} and* {@link Double#compare(double, double)}.*/
public static void assertEquals(double expected, double actual, double delta) {AssertEquals.assertEquals(expected, actual, delta);
}

运行测试:

> mvn test -Dtest=CalculatorTest

注意:-Dtest 的值可以是下列情况之一:

  1. 要运行的测试类名(CalculatorTest);
  2. 测试类的文件名("CalculatorTest.java");
  3. 某个包路下的所有测试("com/manning/junitbook/ch02/disabled/*")。

【小贴士】关于用 -D 表示定义一个变量的写法

该写法最早 继承自 C/C++ 编译器的传统。在 Java 诞生之前,CC++ 的编译器(如 gcc, cc)就已经广泛使用 -D定义宏

gcc -DDEBUG -DVERSION=1.0 myprogram.c

上述命令将在编译时定义了一个 DEBUG 宏(值为1)和一个 VERSION 宏(值为1.0)。

Java 在 1990 年代中期被创建时,它的设计者 James Gosling 本身是 C/C++ 领域的专家。为了让 Java 对开发者显得熟悉和友好,有意借鉴了 C/C++ 编译器的命令行选项风格。因此,用 -D 来表示 定义 某个值。

另外,单字母命令行选项在 Unix 世界中是标准做法。这些选项通常(但并非总是)是其所代表单词的 首字母,例如:

  • -v ➡️ verbose
  • -f ➡️ file
  • -D ➡️ Define
http://www.dtcms.com/a/490977.html

相关文章:

  • 公司门户网站该怎么做用模块做网站
  • 合肥网站定制公司宁波做网站公司哪家好
  • Banana Script,一个C99实现的,类JavaScript极简语法的脚本引擎
  • 14-机器学习与大模型开发数学教程-第1章 1-6 费马定理与极值判定
  • 写的网站怎么做接口php在网站上怎么做充值
  • nginx报400bad request 请求头过大异常处理
  • react+springboot云上部署
  • Google 地图类型
  • 免费网站做企业的网站都要准备什么
  • 网站建设往年的高考题免费看电视的网站有哪些
  • STM32N6 KEIL IDE 调试XIP 应用的一种方法 LAT1575
  • 大模型微调(二):使微调保持稳定的策略
  • 前端调优23大规则(Part 4)
  • SpringBoot-入门介绍
  • 如何推动AI技术在企业管理中的商业化落地?
  • 淘宝网站建设的策划书产品软文案例
  • 复制带随机指针的链表
  • Promise 与 async/await
  • win11 字体变宽问题
  • 最好的做网站机械加工网站色彩搭配
  • Pytorch Yolov11目标检测+Android部署 留贴记录
  • iis 发布网站 404archlinux+wordpress
  • leetcode 2598. 执行操作后的最大 MEX 中等
  • SuperMap iObject Java实现倾斜数据预处理
  • 逻辑方阵(Logical Square)解说
  • Vue与React中动态导入的原理及实现差异解析
  • 有一个网站自己做链接获取朋友位置传媒公司属于什么行业类型
  • 服饰类电商网站建设策划昆山vi设计
  • aben.co微端侧模型价格实惠的服务商
  • 网站开发思维导图内容如何做一个单页面的网站