Test
Introduction
import 'test';The test module runs named checks and reports which ones pass or fail.
import 'test';
int add(int a, int b) {
return a + b;
}
test.start("adds two numbers", void () -> {
test.expectInt(add(2, 3), 5);
});
test.run();
// ok adds two numbers
// 1 passed, 0 failedA test file is an ordinary Nio program:
nio run tests/math.nionio test writes the entry file for you and runs every *_test.nio under a
path — see Testing.
Notes
- A test stops at its first failed assertion, but the remaining tests still run.
- Any uncaught error inside a test is reported as a test failure.
test.startruns a synchronous test immediately.test.startAsyncregisters an async test thattest.runwaits for.- Always call
test.runafter registering tests. It prints the summary and exits with status1if any test failed.
Running only some tests. Every test program accepts --filter <text> and then runs only the tests whose title contains that text. This works whether nio test wrote the entry file or you did:
nio test --filter parser
nio run tests/all.nio --filter parser
nio run tests/all.nio --filter="parser: a union"The text is matched as plain text, not as a pattern, so nothing needs escaping, and one filter can select a whole family of tests. The summary says how many tests were left out:
ok parser: a union declares a sealed base
ok parser: a union member takes one payload
2 passed, 0 failed, 929 filtered outA test registered with test.startAsync is still started when it is filtered out — only its result is hidden — so filtering does not make async tests faster.
Coverage. Run a test program with --coverage to see which lines of your code the tests ran:
nio run --coverage tests/math.nioThis writes coverage.lcov, which most editors and coverage tools can display. Set NIO_COVERAGE_FILE to write it somewhere else.
test.start()
void test.start(String title, Function()<void!> body)Runs body immediately and reports the result under title.
An uncaught error from the body fails the test with that error’s message.
import 'test';
test.start("strings match", void () -> {
test.expectString("nio", "nio");
});test.startAsync()
void test.startAsync(String title, Future<void!> task)Registers an async test. The future is passed directly, and test.run waits for it.
The task must be fallible (Future<void!>), which it becomes when it contains an assertion or another fallible call.
import 'test';
import 'time';
void async completesLater() {
await time.sleep(20);
test.expectBool(true, true);
}
test.startAsync("completes later", completesLater());
test.run();test.assert()
void test.assert(bool ok, String message)Fails the current test with message when ok is false. Use it for conditions that do not have a dedicated expectation.
import 'test';
int[] values = [1, 2, 3];
test.start("has three values", void () -> {
test.assert(values.length == 3, "expected three values");
});test.expectInt()
void test.expectInt(int got, int want)Fails unless got and want are equal. It accepts all integer types and enum values.
import 'test';
test.start("answer is 42", void () -> {
test.expectInt(6 * 7, 42);
});test.expectFloat()
void test.expectFloat(float got, float want)Fails unless the values are exactly equal. Use it for values that are written directly rather than results that may contain floating-point rounding.
import 'test';
test.start("reads a decimal", void () -> {
test.expectFloat(1.5, 1.5);
});test.expectFloatNear()
void test.expectFloatNear(float got, float want, float tolerance)Fails unless the difference between got and want is within tolerance.
import 'test';
test.start("adds decimals", void () -> {
test.expectFloatNear(0.1 + 0.2, 0.3, 0.0001);
});test.expectString()
void test.expectString(String got, String want)Fails unless the strings are equal.
import 'test';
import 'string';
test.start("uppercases a name", void () -> {
test.expectString(string.toUpperCaseAscii("nio"), "NIO");
});test.expectBool()
void test.expectBool(bool got, bool want)Fails unless the boolean values are equal.
import 'test';
test.start("feature is enabled", void () -> {
test.expectBool(true, true);
});test.run()
void test.run()Waits for all tests registered with test.startAsync, prints the total results, and exits with status 1 when anything failed. A successful call returns normally.
import 'test';
test.start("passes", void () -> {
test.expectInt(1, 1);
});
test.run();
// ok passes
// 1 passed, 0 failed