Nushell
安装 Nu !
快速开始
  • Nushell 之书
  • 命令参考列表
  • 实战指南
  • 语言参考指南
  • 贡献指南
博客
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
GitHub
安装 Nu !
快速开始
  • Nushell 之书
  • 命令参考列表
  • 实战指南
  • 语言参考指南
  • 贡献指南
博客
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
GitHub
  • 简介
  • 安装
    • 默认 Shell
  • 快速入门
    • 快速入门
    • 在系统中四处移动
    • 用 Nu 的方式思考
    • Nushell 速查表
  • Nu 基础篇
    • 数据类型
    • 加载数据
    • 管道
    • 处理字符串
    • 处理列表
    • 处理记录(Records)
    • 处理表格
    • 导航和访问结构化数据
    • 特殊变量
  • Nushell 编程
    • 自定义命令
    • 别名
    • 运算符
    • 变量
    • 控制流
    • 脚本
    • 模块
      • 使用模块
      • 创建模块
    • 覆层
    • 排序
    • 测试你的 Nushell 代码
    • 最佳实践
  • Nu 作为 Shell 使用
    • 配置
    • 环境
    • 标准输入、输出和退出码
    • 运行系统(外部)命令
    • 如何配置第三方提示
    • 目录栈
    • Reedline,Nu 的行编辑器
    • 自定义补全
    • 外部命令
    • Nu 的配色和主题
    • 钩子
    • 后台任务
  • 迁移到 Nu
    • 从 Bash 到 Nu
    • 从 CMD.EXE 到 Nu
    • 从其他 Shell 或 DSL 到 Nu
    • 从命令式语言到 Nu
    • 从函数式语言到 Nu
    • Nushell 运算符
  • 设计说明
    • Nushell代码执行原理
  • (不怎么)高级篇
    • 标准库 (预览版)
    • Dataframes
    • 元数据
    • 创建你自己的错误
    • 并行
    • 插件
    • explore

测试你的 Nushell 代码

断言命令

Nushell 在标准库中提供了一组"断言"命令。

我们确实可以使用内置的相等/顺序命令实现测试目的,如 == 或 <= 或更复杂的命令,并在预期条件失败时手动抛出错误,但使用标准库提供的内容可以说更容易!

在下文中,将假设 std assert 模块已在当前作用域中导入

use std/assert

每个断言的基础是 std assert 命令。如果条件不为真,它会生成一个错误。

assert (1 == 2)
Error:
  × Assertion failed.
   ╭─[entry #13:1:1]
 1 │ assert (1 == 2)
   ·         ───┬──
   ·            ╰── It is not true.
   ╰────

可以选择设置一条消息来显示断言命令的意图、出了什么问题或预期是什么:

let a = 0
assert ($a == 19) $"The lockout code is wrong, received: ($a)"
Error:
  × The lockout code is wrong, received: 13
   ╭─[entry #25:1:1]
 1 │ let a = 0
 2 │ assert ($a == 19) $"The lockout code is wrong, received: ($a)"
   ·         ────┬───
   ·             ╰── It is not true.
   ╰────

有许多断言命令,它们的行为与基本命令完全相同,只是使用了适当的运算符。它们的附加价值是能够提供更好的错误消息。

例如,如果没有附加消息,这不是很有帮助:

let a = "foo"
let b = "bar"
assert ($b | str contains $a)
Error:   × Assertion failed.
   ╭─[entry #5:3:8]
 2 │ let b = "bar"
 3 │ assert ($b | str contains $a)
   ·        ───────────┬──────────
   ·                   ╰── It is not true.
   ╰────

而使用 assert str contains:

let a = "a needle"
let b = "haystack"
assert str contains $b $a
Error:   × Assertion failed.
   ╭─[entry #7:3:21]
 2 │ let b = "bar"
 3 │ assert str contains $b $a
   ·                     ──┬──
   ·                       ╰─┤ This does not contain 'a needle'.
   ·                         │         value: "haystack"
   ╰────

一般来说,对于基本的 assert 命令,建议始终提供附加消息来显示出了什么问题。如果你不能使用任何内置的断言命令,你可以通过为 error make 传递标签来为 assert 命令创建一个自定义的:

def "assert even" [number: int] {
    assert ($number mod 2 == 0) --error-label {
        text: $"($number) is not an even number",
        span: (metadata $number).span,
    }
}

然后你就有了详细的自定义错误消息:

let $a = 13
assert even $a
Error:
  × Assertion failed.
   ╭─[entry #37:1:1]
 1 │ assert even $a
   ·             ─┬
   ·              ╰── 13 is not an even number
   ╰────

运行测试

现在我们已经能够通过调用 std assert 中的命令来编写测试,能够运行它们并在出现问题时看到测试失败,在一切正确时看到测试通过,这将是很好的 😃

Nupm 包

在第一种情况下,我们将假设你要测试的代码是 Nupm 包的一部分。

在这种情况下,只需按照以下步骤操作:

  • 在包的 nupm.nuon 包文件旁边创建一个 tests/ 目录
  • 通过向其中添加 mod.nu 文件使 tests/ 目录成为有效模块
  • 在 tests/ 中编写命令
  • 调用 nupm test

约定是,从 tests 模块完全导出的任何命令都将作为测试运行,例如:

  • tests/mod.nu 中的 export def some-test 将运行
  • tests/mod.nu 中的 def just-an-internal-cmd 将不会运行
  • 当且仅当 tests/mod.nu 中有类似 export use spam.nu * 的内容时,tests/spam.nu 中的 export def another-test 才会运行

独立测试

如果你的 Nushell 脚本或模块不是 Nupm 包的一部分,最简单的方法是在独立脚本中编写测试,然后从 Makefile 或 CI 中调用它们:

假设我们有一个简单的 math.nu 模块,其中包含一个简单的斐波那契命令:

# `fib n` 是第 n 个斐波那契数
export def fib [n: int] [ nothing -> int ] {
    if $n == 0 {
        return 0
    } else if $n == 1 {
        return 1
    }

    (fib ($n - 1)) + (fib ($n - 2))
}

然后一个名为 tests.nu 的测试脚本可能如下所示

use math.nu fib
use std/assert

for t in [
    [input, expected];
    [0, 0],
    [1, 1],
    [2, 1],
    [3, 2],
    [4, 3],
    [5, 5],
    [6, 8],
    [7, 13],
] {
    assert equal (fib $t.input) $t.expected
}

并通过 nu tests.nu 调用

基本测试框架

也可以将测试定义为具有描述性名称的函数,并在不需要 Nupm 包的情况下动态发现它们。以下使用 scope commands 和第二个 Nushell 实例来运行生成的测试列表。

use std/assert

source fib.nu

def main [] {
    print "Running tests..."

    let test_commands = (
        scope commands
            | where ($it.type == "custom")
                and ($it.name | str starts-with "test ")
                and not ($it.description | str starts-with "ignore")
            | get name
            | each { |test| [$"print 'Running test: ($test)'", $test] } | flatten
            | str join "; "
    )

    nu --commands $"source ($env.CURRENT_FILE); ($test_commands)"
    print "Tests completed successfully"
}

def "test fib" [] {
    for t in [
        [input, expected];
        [0, 0],
        [1, 1],
        [2, 1],
        [3, 2],
        [4, 3],
        [5, 5],
        [6, 8],
        [7, 13]
    ] {
        assert equal (fib $t.input) $t.expected
    }
}

# ignore
def "test show-ignored-test" [] {
    print "This test will not be executed"
}

这是一个简单的示例,但可以扩展以包含你可能期望的测试框架的许多功能,包括设置和拆卸函数以及跨文件的测试发现。

在GitHub上编辑此页面
Contributors: voyage200🍬
Prev
排序
Next
最佳实践