编写测试#

测试对于提高程序的质量和可维护性很重要。它们验证程序的行为,也作为规范,以避免随时间的推移出现退步。

MoonBit 提供测试支持,使编写测试更加简单和容易。

测试块#

MoonBit 提供测试代码块,用于编写内联测试用例。例如:

test "test_name" {
  assert_eq!(1 + 1, 2)
  assert_eq!(2 + 2, 4)
  inspect!([1, 2, 3], content="[1, 2, 3]")
}

测试代码块本质上是一个返回 Unit 抛出 String 的函数。它在执行 moon test 期间被调用,并通过构建系统输出测试报告。assert_eq 函数来自标准库;如果断言失败,它会打印错误消息并终止测试。字符串 "test_name" 用于标识测试用例,是可选的。

如果测试名称以 "panic" 开头,表示测试的预期行为是触发 panic,只有在触发 panic 时测试才会通过。例如:

test "panic_test" {
  let _ : Int = Option::None.unwrap()

}

快照测试#

在指定预期值时,编写测试可能会很繁琐。因此,MoonBit 提供了三种快照测试。所有这些都可以使用 moon test --update 自动插入或更新。

快照 Show#

我们可以使用 inspect!(x, content="x") 来检查实现了 Show 特征的任何内容。正如我们之前提到的,Show 是一个可以派生的内建特征,提供了 to_string来打印数据结构的内容。标记参数 content 可以省略,因为 moon test --update 会自动插入:

struct X { x : Int } derive(Show)

test "show snapshot test" {
  inspect!({x: 10}, content="{x: 10}")
}

快照 JSON#

派生的 Show 特征的问题是它不能对输出进行格式化,导致输出非常长。

解决方案是使用 @json.inspect!(x, content=x)。其好处是生成的内容是一个 JSON 结构,在格式化后更易读。

enum Rec {
  End
  Really_long_name_that_is_difficult_to_read(Rec)
} derive(Show, ToJson)

test "json snapshot test" {
  let r = Really_long_name_that_is_difficult_to_read(
    Really_long_name_that_is_difficult_to_read(
      Really_long_name_that_is_difficult_to_read(End),
    ),
  )
  inspect!(
    r,
    content="Really_long_name_that_is_difficult_to_read(Really_long_name_that_is_difficult_to_read(Really_long_name_that_is_difficult_to_read(End)))",
  )
  @json.inspect!(
    r,
    content={
      "$tag": "Really_long_name_that_is_difficult_to_read",
      "0": {
        "$tag": "Really_long_name_that_is_difficult_to_read",
        "0": {
          "$tag": "Really_long_name_that_is_difficult_to_read",
          "0": { "$tag": "End" },
        },
      },
    },
  )
}

也可以实现自定义 ToJson 来保留必要的信息。

快照任何内容#

有时我们不仅要记录一个数据结构,还要记录整个过程的输出。

可以使用完整的快照测试使用 @test.T::write@test.T::writeln 记录任何内容:

test "record anything" (t : @test.T) {
  t.write("Hello, world!")
  t.writeln(" And hello, MoonBit!")
  t.snapshot!(filename="record_anything.txt")
}

这将在该包的 __snapshot__ 下创建一个具有给定文件名的文件:

Hello, world! And hello, MoonBit!

这也可以用于测试应用程序的输出,无论是创建图像、视频还是一些自定义数据。

黑盒测试和白盒测试#

在开发库时,验证用户是否可以正确使用它是很重要的。例如,可能会忘记使类型或函数公开。这就是为什么 MoonBit 提供了黑盒测试,允许开发人员了解其他人的感受。

  • 只能访问包中所有成员的测试称为白盒测试,因为我们可以看到一切。这样的测试可以内联定义,也可以在文件中定义,文件名以 _wbtest.mbt 结尾。

  • 只能访问包中公共成员的测试称为黑盒测试。这样的测试需要在文件中定义,文件名以 _test.mbt 结尾。

白盒测试文件(_wbtest.mbt)导入包配置(moon.pkg.json)中的 importwbtest-import 部分定义的包。

黑盒测试文件(_test.mbt)导入当前包和包配置(moon.pkg.json)中的 importtest-import 部分定义的包。