推荐一个超好用的测试工具,值得体验!

news2024/11/27 10:42:27

在软件开发领域中,测试是确保质量与可靠性的必要环节。俗话说得好“工欲善其事,必先利其器”,测试工具越简单、用户友好度越高,开发者编写测试的意愿度就越高。

为了满足大家的测试需求,MoonBit 标准库最近引入了 inspect 函数,我们也称之为 expect 测试,它可以帮助程序员快速编写测试。

相比于 OCaml 和 Rust,MoonBit 提供了更加简洁高效的测试体验。我们的测试工具不仅操作简便,而且无需任何外部依赖,支持开箱即用,简化了测试流程。

这里简单介绍一下 MoonBit

MoonBit 是国内首个工业级编程语言及其配套工具链(https://www.moonbitlang.cn/)
是由粤港澳大湾区数字经济研究院(福田)基础软件中心打造的AI原生的编程语言以及开发者平台。MoonBit自2022年10月推出以来,通过创新框架在程序语言界形成后发优势,已在编译速度、运行速度和程序体积上取得了显著的优势。MoonBit 平台的出现不仅仅作为一种编程语言,更提供一个完整的开发工具链,包括 IDE、编译器、构建系统、包管理器等。

接下来,让我们进一步了解 inspect 函数的使用。

忽略掉与位置相关的参数后,inspect 函数签名为:

pub fn inspect(obj : Show, ~content: String = "")

这里 obj 是任意一个实现 Show 接口的对象,~content 是一个可选参数,表示我们所期望的 obj 转化为字符串后的内容。听起来有点绕?让我们先来看看 inspect 的基本用法:

01 基本用法

首先,让我们使用 moon new hello 创建一个新项目

此时项目的目录结构如下:

.
├── README.md
├── lib
│   ├── hello.mbt
│   ├── hello_test.mbt
│   └── moon.pkg.json
├── main
│   ├── main.mbt
│   └── moon.pkg.json
├── moon.mod.json

打开 lib/hello_test.mbt,将内容替换为:

fn matrix(c: Char, n: Int) -> String {
  let mut m = ""
  for i = 0; i < n; i = i + 1 {
    for j = 0; j < n; j = j + 1 {
      m = m + c.to_string()
    }
    m += "\n"
  }
  m
}

这里,matrix 函数接受一个字符 c 和整数 n 作为参数,生成一个 n * n 大小的字符矩阵。

接下来,添加如下内容:

test {
  inspect(matrix('🤣', 3))?
}

打开终端,执行 moon test 命令可以观察到类似如下输出:

Diff:
----
🤣🤣🤣
🤣🤣🤣
🤣🤣🤣

----

这里的输出展示了 matrix 函数的实际输出和 ~content 参数的差异,执行 moon test -u 或者 moon test --update 可以观察到 lib/hello_test.mbt文件中的测试块被自动更新成:

test {
  inspect(matrix('🤣', 3), ~content=
    #|🤣🤣🤣
    #|🤣🤣🤣
    #|🤣🤣🤣
    #|
  )?
}

让我们再把 n 改成 4,然后执行 moon test -u 可以观察到测试块被自动更新成:

test {
  inspect(matrix('🤣', 4), ~content=
    #|🤣🤣🤣🤣
    #|🤣🤣🤣🤣
    #|🤣🤣🤣🤣
    #|🤣🤣🤣🤣
    #|
  )?
}

在这里插入图片描述

02 稍微复杂的例子

一般来说,写完一个函数后,我们需要为其编写一些单元测试。最简单的是断言测试,MoonBit 标准库中提供了 @assertion.assert_eq 函数,用于判断两个值是否相等。对于上述例子来说测试编写相对容易,因为我们可以轻易预测输出结果是什么。

接下来让我们看一个稍微复杂一点的例子:如何测试计算斐波那契数列第 n 项的函数。

首先在 lib 目录下新建一个 fib.mbt 的文件,然后粘贴如下内容:

fn fib(n : Int) -> Int {
  match n {
    0 => 0
    1 => 1
    _ => fib(n - 1) + fib(n - 2)
  }
}

我们需要一些测试来验证我们的实现是否正确。如果用断言测试,那么编写测试的流程是什么呢?假设我们想测试输入为 10 时 fib的结果,我们会写下类似如下的代码:

test {
  @assertion.assert_eq(fib(10), ???)?
}

当我们写下这个测试的时候,会立即遇到一个问题,我们并不知道 assert_eq 中右侧的期望值应该是什么。我们可以自己在纸上计算,或者找一份斐波那契数列参考列表、或者执行我们自己实现的 fib 函数。总之,不论用什么方法,我们需要得到 fib(10) 的期望值是 55,才能完成一个测试用例的编写。

此时 lib/fib.mbt 文件内容应为:

fn fib(n : Int) -> Int {
  match n {
    0 => 0
    1 => 1
    _ => fib(n - 1) + fib(n - 2)
  }
}

test {
  @assertion.assert_eq(fib(10), 55)?
}

然后执行 moon test 可以观察到如下输出:

Total tests: 2, passed: 2, failed: 0.

大家可以感受到,这里的反馈周期是很长的。通常来说,用这种方法编写测试并不是很愉悦。

对于 fib 这个例子我们可以相对容易找到一个正确的值作为参考。然而,大多数情况下,我们想测试的函数并没有其他“真值表”作为参考。我们需要做的是给这个函数提供输入,然后观察其输出是否符合我们的期望。这种模式比较常见,但其他工具链很少提供支持。因此,我们的 MoonBit 工具链提供了对这一测试模式的一等支持。通过使用 inspect 函数,我们只需要提供输入,而不需要提供期望值。

接下来,让我们用 inspect 函数编写输入分别为 8,9,10 时的测试用例,此时 lib/fib.mbt 文件的内容如下:

fn fib(n : Int) -> Int {
  match n {
    0 => 0
    1 => 1
    _ => fib(n - 1) + fib(n - 2)
  }
}

test {
  @assertion.assert_eq(fib(10), 55)?
}

test {
  inspect(fib(8))?
}

test {
  inspect(fib(9))?
}

test {
  inspect(fib(10))?
}

通过执行:

moon test

可以观察到实际输出与 inspect 函数中 ~content的差异:

$ moon test
test username/hello/lib/fib.mbt::0 failed
expect test failed at path/to/lib/fib.mbt:10:3-10:18
Diff:
----
21
----

test username/hello/lib/fib.mbt::1 failed
expect test failed at path/to/lib/fib.mbt:14:3-14:18
Diff:
----
34
----

test username/hello/lib/fib.mbt::2 failed
expect test failed at path/to/lib/fib.mbt:18:3-18:19
Diff:
----
55
----

接下来,我们的工作变成了检查这个输出是否正确,如果确信这些输出是正确的,通过执行 moon test -u,在 lib/fib.mbt 文件中对应的测试块会被自动更新成:

test {
  inspect(fib(8), ~content="21")?
}

test {
  inspect(fib(9), ~content="34")?
}

test {
  inspect(fib(10), ~content="55")?
}

通过这种编写测试然后立即获取反馈的模式,能够极大提升编写测试的愉悦感。

接下来,让我们来看一个修改函数行为导致输出变化的例子。

例如,我们现在想让 fib 的第一项从 1 而不是从 0 开始,首先我们将 fib 函数中的 0 => 0 修改为 0 => 1:

fn fib(n : Int) -> Int {
  match n {

在这里插入图片描述

然后执行 moon test 可以看到 expect test 自动为我们展示了前后差异:

$ moon test
test username/hello/lib/fib.mbt::0 failed: FAILED:path/to/lib/fib.mbt:10:3-10:36 `89 == 55`
test username/hello/lib/fib.mbt::1 failed
expect test failed at path/to/lib/fib.mbt:14:3-14:33
Diff:
----
2134
----

test username/hello/lib/fib.mbt::2 failed
expect test failed at path/to/lib/fib.mbt:18:3-18:33
Diff:
----
3455
----

test username/hello/lib/fib.mbt::3 failed
expect test failed at path/to/lib/fib.mbt:22:3-22:34
Diff:
----
5589
----

Total tests: 5, passed: 1, failed: 4.

这里的输出结果发生了位移,符合期望,我们大概率可以确定输出是对的。于是通过执行 moon test -u 自动更新测试结果。

在这里插入图片描述

等等!为什么自动更新后,还有一个测试用例失败了呢?

Total tests: 5, passed: 4, failed: 1.

这是因为我们忘记了修改断言测试,与 expect 测试不同,断言测试并不会自动更新。我们需要手动将断言测试对应的测试块修改为:

test {
  @assertion.assert_eq(fib(10), 89)?
}

从这个例子也能看出来,expect 测试是可以与断言测试协同工作的。

重新执行 moon test,可以看到全部测试都通过了。

Total tests: 5, passed: 5, failed: 0.

想象一下,如果我们之前有数百个断言测试,修改起来将会非常麻烦。通过使用 expect 测试,可以让我们从枯燥的更新工作中解脱出来。

以上,我们通过两个例子展示了它们如何通过编写测试并获得即时反馈,显著提升测试效率的能力。

我们鼓励你尝试使用 MoonBit 的 expect 测试,体验其在实际应用中的便利和高效。

推荐阅读:

https://blog.janestreet.com/the-joy-of-expect-tests/

你还可以了解更多内容:

  • 如何开始使用 MoonBit
  • 详细的 MoonBit 文档
  • 添加微信小助手moonbit_helper,加入 MoonBit 用户群。
  • MoonBit 标准库现已开源,查看指南了解如何进行贡献。

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

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

相关文章

基于Python的景区票务人脸识别系统(V2.0)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

安装SSMS出现错误和SSMS连接数据库失败

1.点击图片下安装的时候&#xff0c;出现0x80070643错误 解决办法&#xff1a; 1,如果是是第一次安装的话&#xff0c;重新启动电脑&#xff0c;把原来下载的SSMS删除掉&#xff0c;在重新下载安装 2.如果是原来就下载过&#xff0c;先…

基于Docker构建CI/CD工具链(七)使用Jmeter进行自动化压测

上一篇文章中&#xff0c;我们详细介绍了构建 Apifox Cli 的 Docker 镜像的步骤&#xff0c;并通过简单的示例演示了如何利用 GitLab 的 CI/CD 功能&#xff0c;将构建好的镜像利用在自动化测试作业中。在今天的文章中&#xff0c;我们将重点讨论如何构建 JMeter 的 Docker 镜像…

彻底解决 pyshark 库 TShark not found

使用 python 运行 github 某个项目处理 pcap 包时遇到如下报错&#xff1a; &#xff08;先安装了 pyshark 库&#xff09; pyshark.tshark.tshark.TSharkNotFoundException: TShark not found. Try adding its location to the configuration file. Searched these paths: […

现在谷歌企业号需要验证企业官网和法人信息,才能注册成功或提审应用?

众所周知&#xff0c;近年来&#xff0c;随着谷歌上架行业的发展&#xff0c;以及开发者们上架马甲包或矩阵式上架的操作&#xff0c;谷歌官方对于开发者账号的审核越来越严格了。 从一开始需要提供收付款卡银行流水账单&#xff0c;到后续引入邓白氏码等更为严格的账号验证机制…

【学习笔记】Vue3源码解析:第四部分- runtime-dom(1)

课程地址&#xff1a;【已完结】全网最详细Vue3源码解析&#xff01;&#xff08;一行行带你手写Vue3源码&#xff09; 第四部分-&#xff1a;&#xff08;对应课程的第24-26节&#xff09; 第24节&#xff1a;《理解runtime-dom的作用》 源码中除了 dep.ts &#xff0c;其余基…

00_Qt概述以及如何创建一个QT新项目

Qt概述 1.Qt概述1.1 什么是Qt1.2 Qt的发展史1.3 支持的平台1.4 Qt版本1.5 Qt的下载与安装1.6 Qt的优点 2.QT新项目创建3.pro文件4.主函数5.代码命名规范和快捷键 1.Qt概述 1.1 什么是Qt Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面…

边缘计算网关主要有哪些功能?-天拓四方

随着物联网&#xff08;IoT&#xff09;的快速发展和普及&#xff0c;边缘计算网关已经成为了数据处理和传输的重要枢纽。作为一种集成数据采集、协议转换、数据处理、数据聚合和远程控制等多种功能的设备&#xff0c;边缘计算网关在降低网络延迟、提高数据处理效率以及减轻云数…

loD:如何实现代码的“高内聚、低耦合“

设计模式专栏&#xff1a;http://t.csdnimg.cn/3a25S 目录 1.引用 2.何为"高内聚、低耦合" 3.LoD 的定义描述 4.定义解读与代码示例一 5.定义解读与代码示例二 1.引用 本节介绍最后一个设计原则:LoD(Law of Demeter&#xff0c;迪米特法则)。尽LoD不像SOLID、KI…

面试:lock 和 synchronized

一、语法层面 synchronized 是关键字&#xff0c;源码在jvm中&#xff0c;用c语言实现Lock 是接口&#xff0c;源码由jdk提供&#xff0c;用java语言实现使用synchronized时&#xff0c;退出同步代码块锁会自动释放&#xff0c;而使用Lock时&#xff0c;需要手动调用unlock方法…

Linux中进程和计划任务

一.程序 1.什么是程序 &#xff08;1&#xff09;是一组计算机能识别和执行的指令&#xff0c;运行于电子计算机上&#xff0c;满足人们某种需求的信息化工具 &#xff08;2&#xff09;用于描述进程要完成的功能&#xff0c;是控制进程执行的指令集 二.进程 1.什么是进程…

量化过程信息损耗分析(MATLAB)

MATLAB代码 clear_all; Mrand(5,5)*100;% 假设M是待转换的矩阵 a min(M(:)); b max(M(:));% 将M映射到[0, 255] M_mapped functionA(M, a, b); M_mapped_floorfloor(M_mapped); % 将M_mapped恢复到原始范围 M_original functionB(M_mapped_floor, a, b);disp(M); disp(M_m…

【吊打面试官系列】Java高并发篇 - 什么是多线程中的上下文切换?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是多线程中的上下文切换&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是多线程中的上下文切换&#xff1f; 在上下文切换过程中&#xff0c;CPU 会停止处理当前运行的程序&#xff0c;并保存当前程序运行…

【Altium Designer 20 笔记】PCB铺铜过程

PCB铺铜步骤 切换到Keep-Out Layer&#xff08;禁止布线层&#xff09; 使用shifts键切换单层显示 画禁止布线范围&#xff08;防止铺铜过大&#xff09; 切换到需要铺铜的层 选择铺铜网络&#xff0c;通常是地&#xff08;GND&#xff09;或某个电源网络 隐藏覆铜&#xff1a;…

为什么说linux操作系统要比windows稳定?

正常人说windows的时候是指一整套桌面系统&#xff0c;而说linux的时候是一个命令行内核。后者从原理上就比前者稳定。 如果你日常使用的是linux的发行版桌面系统&#xff0c;看到这话估计直接想骂娘。就我12年的ubuntu使用体验来说&#xff0c;定期备份系统是必须的&#xff…

MySQL DDL 通用语法

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

NIO学习

文章目录 前言一、主要模块二、使用步骤1.服务器端2.客户端 三、NIO零拷贝(推荐)四、NIO另一种copy总结 前言 NIO是JDK1.4版本带来的功能,区别于以往的BIO编程,同步非阻塞极大的节省资源开销&#xff0c;避免了线程切换和上下文切换带来的资源浪费。 一、主要模块 Selector&a…

C++设计模式|创建型 2.工厂模式

1.简单工厂思想 简单工厂模式不属于23种设计模式之⼀&#xff0c;更多的是⼀种编程习惯。它的核心思想是将产品的创建过程封装在⼀个⼯⼚类中&#xff0c;把创建对象的流程集中在这个⼯⼚类⾥⾯。卡码网将其结构描述为下图所示的情况&#xff1a; 简单⼯⼚模式包括三个主要⻆⾊…

【STL详解 —— priority_queue的使用与模拟实现】

STL详解 —— priority_queue的使用与模拟实现 priority_queue的使用priority_queue的介绍priority_queue的定义方式priority_queue各个接口的使用 priority_queue的模拟实现仿函数priority_queue的模拟实现 priority_queue的使用 priority_queue的介绍 std::priority_queue 是…

基于Echarts的超市销售可视化分析系统(数据+程序+论文

本论文旨在研究Python技术和ECharts可视化技术在超市销售数据分析系统中的应用。本系统通过对超市销售数据进行分析和可视化展示&#xff0c;帮助决策层更好地了解销售情况和趋势&#xff0c;进而做出更有针对性的决策。本系统主要包括数据处理、数据可视化和系统测试三个模块。…