Home Explore Blog CI



nushell

2nd chunk of `book/testing.md`
336fa0ad04fb11f6f997f7cde0d7cc8890ad4fb5ee0bd5990000000100000fa6
   ·                         │         value: "haystack"
   ╰────
```

In general for base `assert` command it is encouraged to always provide the additional message to show what went wrong. If you cannot use any built-in assert command, you can create a custom one with passing the label for [`error make`](/commands/docs/error_make.md) for the `assert` command:

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

Then you'll have your detailed custom error message:

```nu
let $a = 13
assert even $a
```

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

## Running the Tests

Now that we are able to write tests by calling commands from `std assert`, it would be great to be able to run them and see our tests fail when there is an issue and pass when everything is correct :)

### Nupm Package

In this first case, we will assume that the code you are trying to test is part of a [Nupm] package.

In that case, it is as easy as following the following steps

- create a `tests/` directory next to the `nupm.nuon` package file of your package
- make the `tests/` directory a valid module by adding a `mod.nu` file into it
- write commands inside `tests/`
- call `nupm test`

The convention is that any command fully exported from the `tests` module will be run as a test, e.g.

- `export def some-test` in `tests/mod.nu` will run
- `def just-an-internal-cmd` in `tests/mod.nu` will NOT run
- `export def another-test` in `tests/spam.nu` will run if and only if there is something like `export use spam.nu *` in `tests/mod.nu`

### Standalone Tests

If your Nushell script or module is not part of a [Nupm] package, the simplest way is to write tests in standalone scripts and then call them, either from a `Makefile` or in a CI:

Let's say we have a simple `math.nu` module which contains a simple Fibonacci command:

```nu
# `fib n` is the n-th Fibonacci number
export def fib [n: int] [ nothing -> int ] {
    if $n == 0 {
        return 0
    } else if $n == 1 {
        return 1
    }

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

then a test script called `tests.nu` could look like

```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
}
```

and be invoked as `nu tests.nu`

### Basic Test Framework

It is also possible to define tests in Nushell as functions with descriptive names and discover
them dynamically without requiring a [Nupm] package. The following uses `scope commands` and a
second instance of Nushell to run the generated list of tests.

```nu
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"
}
```

This is a simple example but could be extended to include many of the things you might expect from
a testing framework, including setup and tear down functions and test discovery across files.


Title: Running Nushell Tests: Nupm Packages, Standalone Scripts, and Basic Framework
Summary
Nushell tests can be run in different ways. For Nupm packages, create a `tests/` directory, make it a module with `mod.nu`, and use `nupm test`. Exported commands in `tests/mod.nu` are run as tests. For standalone scripts, write tests and call them using `nu tests.nu`. A basic test framework can dynamically discover and run tests defined as functions with descriptive names by using `scope commands` and another Nushell instance.