You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* remove mentions to hidden `std testing` module
* minor fixes
- `use std assert` at the start
- consistently call `assert ...` instead of `std assert ...`
- split "command" and output blocks
- merge `span` and `end` into `span` for the last example
* write a section to run tests
* fix spelling
To ensure that your code works as expected, you can use the [testing module](https://github.com/nushell/nushell/blob/main/crates/nu-std/testing.nu).
4
-
5
-
## Quick start
6
-
7
-
Download the [testing module](https://raw.githubusercontent.com/nushell/nushell/main/crates/nu-std/testing.nu) and save it as `testing.nu` in the folder with your project.
3
+
## Assert commands
8
4
9
-
Have a file, called `test_math.nu`:
5
+
Nushell provides a set of "assertion" commands in the standard library.
6
+
One could use built-in equality / order tests such as `==` or `<=` or more complex commands and throw errors manually when an expected condition fails, but using what the standard library has to offer is arguably easier!
10
7
11
-
```nu
8
+
In the following, it will be assumed that the `std assert` module has been imported inside the current scope
9
+
```nushell
12
10
use std assert
13
-
14
-
#[test]
15
-
def test_addition [] {
16
-
assert equal (1 + 2) 3
17
-
}
18
-
19
-
#[test]
20
-
#[ignore]
21
-
def test_skip [] {
22
-
# this won't be run
23
-
}
24
-
25
-
#[test]
26
-
def test_failing [] {
27
-
assert false "This is just for testing"
28
-
}
29
11
```
30
12
31
-
Run the tests:
13
+
The foundation for every assertion is the `std assert` command. If the condition is not true, it makes an error.
32
14
33
15
```nu
34
-
❯ use testing.nu run-tests
35
-
❯ run-tests
36
-
INF|2023-04-12T10:42:29.099|Running tests in test_math
37
-
Error:
38
-
× This is just for testing
39
-
╭─[C:\wip\test_math.nu:13:1]
40
-
13 │ def test_failing [] {
41
-
14 │ assert false "This is just for testing"
42
-
· ──┬──
43
-
· ╰── It is not true.
44
-
15 │ }
45
-
╰────
46
-
47
-
48
-
WRN|2023-04-12T10:42:31.086|Test case test_skip is skipped
49
-
Error:
50
-
× some tests did not pass (see complete errors above):
51
-
│
52
-
│ test_math test_addition
53
-
│ ⨯ test_math test_failing
54
-
│ s test_math test_skip
55
-
│
16
+
assert (1 == 2)
17
+
```
56
18
```
57
-
58
-
## Assert commands
59
-
60
-
The foundation for every assertion is the `std assert` command. If the condition is not true, it makes an error. For example:
61
-
62
-
```nu
63
-
❯ use std assert
64
-
❯ std assert (1 == 2)
65
19
Error:
66
20
× Assertion failed.
67
21
╭─[entry #13:1:1]
68
-
1 │ std assert (1 == 2)
69
-
· ───┬──
70
-
· ╰── It is not true.
22
+
1 │ assert (1 == 2)
23
+
· ───┬──
24
+
· ╰── It is not true.
71
25
╰────
72
26
```
73
27
74
28
Optionally, a message can be set to show the intention of the assert command, what went wrong or what was expected:
@@ -89,46 +47,56 @@ There are many assert commands, which behave exactly as the base one with the pr
89
47
For example this is not so helpful without additional message:
90
48
91
49
```nu
92
-
❯ std assert ($b | str contains $a)
93
-
Error:
94
-
× Assertion failed.
95
-
╭─[entry #35:1:1]
96
-
1 │ assert ($b | str contains $a)
97
-
· ──────┬─────
98
-
· ╰── It is not true.
50
+
let a = "foo"
51
+
let b = "bar"
52
+
assert ($b | str contains $a)
53
+
```
54
+
```
55
+
Error: × Assertion failed.
56
+
╭─[entry #5:3:8]
57
+
2 │ let b = "bar"
58
+
3 │ assert ($b | str contains $a)
59
+
· ───────────┬──────────
60
+
· ╰── It is not true.
99
61
╰────
100
62
```
101
63
102
64
While with using `assert str contains`:
103
65
104
66
```nu
105
-
❯ std assert str contains $b $a
106
-
Error:
107
-
× Assertion failed.
108
-
╭─[entry #34:1:1]
109
-
1 │ assert str contains $b $a
67
+
let a = "a needle"
68
+
let b = "haystack"
69
+
assert str contains $b $a
70
+
```
71
+
```
72
+
Error: × Assertion failed.
73
+
╭─[entry #7:3:21]
74
+
2 │ let b = "bar"
75
+
3 │ assert str contains $b $a
110
76
· ──┬──
111
-
· ╰── 'haystack' does not contain 'a needle'.
77
+
· ╰─┤ This does not contain 'a needle'.
78
+
· │ value: "haystack"
112
79
╰────
113
80
```
114
81
115
82
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:
116
83
117
84
```nu
118
85
def "assert even" [number: int] {
119
-
std assert ($number mod 2 == 0) --error-label {
120
-
start: (metadata $number).span.start,
121
-
end: (metadata $number).span.end,
86
+
assert ($number mod 2 == 0) --error-label {
122
87
text: $"($number) is not an even number",
88
+
span: (metadata $number).span,
123
89
}
124
90
}
125
91
```
126
92
127
93
Then you'll have your detailed custom error message:
128
94
129
95
```nu
130
-
❯ let $a = 13
131
-
❯ assert even $a
96
+
let $a = 13
97
+
assert even $a
98
+
```
99
+
```
132
100
Error:
133
101
× Assertion failed.
134
102
╭─[entry #37:1:1]
@@ -138,29 +106,63 @@ Error:
138
106
╰────
139
107
```
140
108
141
-
## Test modules & test cases
109
+
## Running the tests
142
110
143
-
The naming convention for test modules is `test_<your_module>.nu`and `test_<test name>` for test cases.
111
+
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 :)
144
112
145
-
In order for a function to be recognized as a test by the test runner it needs to be annotated with `#[test]`.
146
113
147
-
The following annotations are supported by the test runner:
114
+
### Nupm package
148
115
149
-
- test - test case to be executed during test run
150
-
- test-skip - test case to be skipped during test run
151
-
- before-all - function to run at the beginning of test run. Returns a global context record that is piped into every test function
152
-
- before-each - function to run before every test case. Returns a per-test context record that is merged with global context and piped into test functions
153
-
- after-each - function to run after every test case. Receives the context record just like the test cases
154
-
- after-all - function to run after all test cases have been executed. Receives the global context record
116
+
In this first case, we will assume that the code you are trying to test is part of a [Nupm] package.
155
117
156
-
The standard library itself is tested with this framework, so you can find many examples in the [Nushell repository](https://github.com/nushell/nushell/blob/main/crates/nu-std/tests/).
118
+
In that case, it is as easy as following the following steps
119
+
- create a `tests/` directory next to the `nupm.nuon` package file of your package
120
+
- make the `tests/` directory a valid module by adding a `mod.nu` file into it
121
+
- write commands inside `tests/`
122
+
- call `nupm test`
157
123
158
-
## Setting verbosity
124
+
The convention is that any command fully exported from the `tests` module will be run as a test, e.g.
125
+
-`export def some-test` in `tests/mod.nu` will run
126
+
-`def just-an-internal-cmd` in `tests/mod.nu` will NOT run
127
+
-`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`
159
128
160
-
The `testing.nu` module uses the `log` commands from the standard library to display information, so you can set `NU_LOG_LEVEL` if you want more or less details:
161
129
162
-
```nu
163
-
❯ use testing.nu run-tests
164
-
❯ NU_LOG_LEVEL=DEBUG run-tests
165
-
❯ NU_LOG_LEVEL=WARNING run-tests
130
+
### Standalone tests
131
+
132
+
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:
133
+
134
+
Let's say we have a simple `math.nu` module which contains a simple Fibonacci command:
135
+
```nushell
136
+
# `fib n` is the n-th Fibonacci number
137
+
export def fib [n: int] [ nothing -> int ] {
138
+
if $n == 0 {
139
+
return 0
140
+
} else if $n == 1 {
141
+
return 1
142
+
}
143
+
144
+
(fib ($n - 1)) + (fib ($n - 2))
145
+
}
166
146
```
147
+
then a test script called `tests.nu` could look like
0 commit comments