Skip to content
Menu
Contents

Tests

Chapter 9 of 9

Checking that your code works, right next to it.

Tests

In Bert, tests live in the same file as the code they check. Testing is built in: there is nothing to install and no test framework to pick.

A test sits right below the code it checks. It is a test block with a name:

shapes.bert
area : (Int, Int) -> Int
area = (w, h) -> w * h

test "area multiplies" {
  expect(area(4, 5), \(a) -> a == 20)
  expect(area(0, 5), \(a) -> a == 0)
}

When you build or run your program normally, test blocks are ignored. They only run when you ask:

bert test shapes.bert
Output
running 1 test from shapes.bert

  ✓ area multiplies  (2 assertions)

1 passed, 0 failed  (2 assertions)

How expect works

expect takes two things:

  • the value you want to check, like area(4, 5)
  • a check: a small function that gets that value and says true if it is right

Why two parts and not just expect(area(4, 5) == 20)? When a check fails, Bert prints the value it was given. You see what the code actually produced without adding any print lines.

To see a failure, add this below the first test in the same file, and run bert test shapes.bert again:

shapes.bert
test "a failing one" {
  expect(area(1, 1), \(a) -> a == 2)
}
Output
running 2 tests from shapes.bert

  ✓ area multiplies  (2 assertions)
  ✗ a failing one  (1 of 1 assertion failed)
      shapes.bert:10  expect(area(1, 1), \(a) -> a == 2)
          value: 1

1 passed, 1 failed  (3 assertions, 1 failed)

The output points at the file and line, and shows value: 1. The command exits with an error code when anything fails, so it works in automated checks too.

The rules

  • Setup goes first. Inside a test you can name values, just like in a function. Use them in the checks below.
  • The last line must be an expect. A test exists to check something.
  • Every expect runs. A failure does not stop the rest, so one run shows you all the problems.
  • Tests can use private code. They sit in the same module, so they can call helpers that the export line hides (see Modules).
  • Only inside tests. expect does not exist anywhere else.
test "setup first, then check" {
  big = area(4, 5)
  expect(big, \(a) -> a == 20)
  expect(big, \(a) -> a > 10)
}

bert test also runs the tests of every module your file uses, and groups the results by module. Tests in Bert's own standard library are left out.

Quick list of surprises

Warning

No return. No loops. No &&, || or !. No string interpolation. Every line in a { } block except the last must be a line of the form name = .... To run something and ignore the result, write _ = WasiCli.print(…). The pipe passes the value first: x |> f(a) is f(x, a).

Next steps

You have seen the core of the language. The tutorials use a little more, such as types with an @ and JSON decoders, and explain them as they go. Where to go from here: