2019-01-06 14:19:15 -05:00
|
|
|
# Testing
|
2019-01-03 14:16:15 -05:00
|
|
|
|
2019-01-15 21:57:40 -05:00
|
|
|
This module provides a few basic utilities to make testing easier and
|
|
|
|
consistent in Deno.
|
|
|
|
|
2019-01-03 14:16:15 -05:00
|
|
|
## Usage
|
|
|
|
|
2019-01-15 21:57:40 -05:00
|
|
|
The module exports a `test` function which is the test harness in Deno. It
|
|
|
|
accepts either a function (including async functions) or an object which
|
|
|
|
contains a `name` property and a `fn` property. When running tests and
|
|
|
|
outputting the results, the name of the past function is used, or if the
|
2019-03-18 11:08:01 -04:00
|
|
|
object is passed, the `name` property is used to identify the test. If the assertion is false an `AssertionError` will be thrown.
|
2019-01-15 21:57:40 -05:00
|
|
|
|
2019-03-06 16:39:50 -05:00
|
|
|
Asserts are exposed in `testing/asserts.ts` module.
|
2019-01-15 21:57:40 -05:00
|
|
|
|
2019-03-26 11:29:12 -04:00
|
|
|
- `equal()` - Deep comparision function, where `actual` and `expected` are
|
2019-03-06 16:39:50 -05:00
|
|
|
compared deeply, and if they vary, `equal` returns `false`.
|
2019-01-15 21:57:40 -05:00
|
|
|
- `assert()` - Expects a boolean value, throws if the value is `false`.
|
2019-03-06 19:42:24 -05:00
|
|
|
- `assertEquals()` - Uses the `equal` comparison and throws if the `actual` and
|
2019-01-15 21:57:40 -05:00
|
|
|
`expected` are not equal.
|
2019-03-18 11:08:01 -04:00
|
|
|
- `assertNotEquals()` - Uses the `equal` comparison and throws if the `actual` and
|
|
|
|
`expected` are equal.
|
2019-03-06 16:39:50 -05:00
|
|
|
- `assertStrictEq()` - Compares `actual` and `expected` strictly, therefore
|
2019-01-15 21:57:40 -05:00
|
|
|
for non-primitives the values must reference the same instance.
|
2019-03-18 11:08:01 -04:00
|
|
|
- `assertStrContains()` - Make an assertion that `actual` contains `expected`.
|
|
|
|
- `assertMatch()` - Make an assertion that `actual` match RegExp `expected`.
|
|
|
|
- `assertArrayContains()` - Make an assertion that `actual` array contains the `expected` values.
|
2019-03-06 16:39:50 -05:00
|
|
|
- `assertThrows()` - Expects the passed `fn` to throw. If `fn` does not throw,
|
2019-01-15 21:57:40 -05:00
|
|
|
this function does. Also compares any errors thrown to an optional expected
|
|
|
|
`Error` class and checks that the error `.message` includes an optional
|
|
|
|
string.
|
2019-03-06 16:39:50 -05:00
|
|
|
- `assertThrowsAsync()` - Expects the passed `fn` to be async and throw (or
|
2019-01-22 01:15:25 -05:00
|
|
|
return a `Promise` that rejects). If the `fn` does not throw or reject, this
|
|
|
|
function will throw asynchronously. Also compares any errors thrown to an
|
|
|
|
optional expected `Error` class and checks that the error `.message` includes
|
|
|
|
an optional string.
|
2019-03-18 11:08:01 -04:00
|
|
|
- `unimplemented()` - Use this to stub out methods that will throw when invoked
|
|
|
|
- `unreachable()` - Used to assert unreachable code
|
2019-01-15 21:57:40 -05:00
|
|
|
|
2019-03-26 11:29:12 -04:00
|
|
|
`runTests()` executes the declared tests. It accepts a `RunOptions` parameter:
|
|
|
|
|
|
|
|
- parallel : Execute tests in a parallel way.
|
|
|
|
- exitOnFail : if one test fails, test will throw an error and stop the tests. If not all tests will be processed.
|
2019-01-29 15:10:40 -05:00
|
|
|
|
2019-01-15 21:57:40 -05:00
|
|
|
Basic usage:
|
|
|
|
|
2019-01-03 14:16:15 -05:00
|
|
|
```ts
|
2019-03-06 16:39:50 -05:00
|
|
|
import { runTests, test } from "https://deno.land/std/testing/mod.ts";
|
2019-03-06 19:42:24 -05:00
|
|
|
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
|
2019-01-03 14:16:15 -05:00
|
|
|
|
|
|
|
test({
|
2019-01-06 14:19:15 -05:00
|
|
|
name: "testing example",
|
2019-01-03 14:16:15 -05:00
|
|
|
fn() {
|
2019-04-05 07:19:13 -04:00
|
|
|
assertEquals("world", "world");
|
|
|
|
assertEquals({ hello: "world" }, { hello: "world" });
|
2019-01-06 14:19:15 -05:00
|
|
|
}
|
2019-01-03 14:16:15 -05:00
|
|
|
});
|
2019-01-29 15:10:40 -05:00
|
|
|
|
|
|
|
runTests();
|
2019-01-03 14:16:15 -05:00
|
|
|
```
|
|
|
|
|
|
|
|
Short syntax (named function instead of object):
|
2019-01-06 14:19:15 -05:00
|
|
|
|
2019-01-03 14:16:15 -05:00
|
|
|
```ts
|
|
|
|
test(function example() {
|
2019-04-05 07:19:13 -04:00
|
|
|
assertEquals("world", "world");
|
|
|
|
assertEquals({ hello: "world" }, { hello: "world" });
|
2019-01-15 21:57:40 -05:00
|
|
|
});
|
|
|
|
```
|
|
|
|
|
2019-03-06 16:39:50 -05:00
|
|
|
Using `assertStrictEq()`:
|
2019-01-15 21:57:40 -05:00
|
|
|
|
|
|
|
```ts
|
|
|
|
test(function isStrictlyEqual() {
|
|
|
|
const a = {};
|
|
|
|
const b = a;
|
2019-03-06 16:39:50 -05:00
|
|
|
assertStrictEq(a, b);
|
2019-01-15 21:57:40 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
// This test fails
|
|
|
|
test(function isNotStrictlyEqual() {
|
|
|
|
const a = {};
|
|
|
|
const b = {};
|
2019-03-06 16:39:50 -05:00
|
|
|
assertStrictEq(a, b);
|
2019-01-15 21:57:40 -05:00
|
|
|
});
|
|
|
|
```
|
|
|
|
|
2019-03-06 16:39:50 -05:00
|
|
|
Using `assertThrows()`:
|
2019-01-15 21:57:40 -05:00
|
|
|
|
|
|
|
```ts
|
|
|
|
test(function doesThrow() {
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(() => {
|
2019-01-15 21:57:40 -05:00
|
|
|
throw new TypeError("hello world!");
|
|
|
|
});
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(() => {
|
2019-01-15 21:57:40 -05:00
|
|
|
throw new TypeError("hello world!");
|
|
|
|
}, TypeError);
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(
|
2019-01-15 21:57:40 -05:00
|
|
|
() => {
|
|
|
|
throw new TypeError("hello world!");
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"hello"
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// This test will not pass
|
|
|
|
test(function fails() {
|
2019-03-06 16:39:50 -05:00
|
|
|
assertThrows(() => {
|
2019-01-15 21:57:40 -05:00
|
|
|
console.log("Hello world");
|
|
|
|
});
|
2019-01-03 14:16:15 -05:00
|
|
|
});
|
2019-01-04 05:09:42 -05:00
|
|
|
```
|
2019-01-22 01:15:25 -05:00
|
|
|
|
2019-03-06 16:39:50 -05:00
|
|
|
Using `assertThrowsAsync()`:
|
2019-01-22 01:15:25 -05:00
|
|
|
|
|
|
|
```ts
|
|
|
|
test(async function doesThrow() {
|
2019-03-19 13:22:33 -04:00
|
|
|
await assertThrowsAsync(async () => {
|
2019-01-22 01:15:25 -05:00
|
|
|
throw new TypeError("hello world!");
|
|
|
|
});
|
2019-03-19 13:22:33 -04:00
|
|
|
await assertThrowsAsync(async () => {
|
2019-01-22 01:15:25 -05:00
|
|
|
throw new TypeError("hello world!");
|
|
|
|
}, TypeError);
|
2019-03-19 13:22:33 -04:00
|
|
|
await assertThrowsAsync(
|
2019-01-22 01:15:25 -05:00
|
|
|
async () => {
|
|
|
|
throw new TypeError("hello world!");
|
|
|
|
},
|
|
|
|
TypeError,
|
|
|
|
"hello"
|
|
|
|
);
|
2019-03-19 13:22:33 -04:00
|
|
|
await assertThrowsAsync(async () => {
|
2019-01-22 01:15:25 -05:00
|
|
|
return Promise.reject(new Error());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// This test will not pass
|
|
|
|
test(async function fails() {
|
2019-03-19 13:22:33 -04:00
|
|
|
await assertThrowsAsync(async () => {
|
2019-01-22 01:15:25 -05:00
|
|
|
console.log("Hello world");
|
|
|
|
});
|
|
|
|
});
|
|
|
|
```
|
2019-03-11 14:21:13 -04:00
|
|
|
|
|
|
|
### Benching Usage
|
|
|
|
|
|
|
|
Basic usage:
|
|
|
|
|
|
|
|
```ts
|
|
|
|
import { runBenchmarks, bench } from "https://deno.land/std/testing/bench.ts";
|
|
|
|
|
|
|
|
bench(function forIncrementX1e9(b) {
|
|
|
|
b.start();
|
|
|
|
for (let i = 0; i < 1e9; i++);
|
|
|
|
b.stop();
|
|
|
|
});
|
|
|
|
|
|
|
|
runBenchmarks();
|
|
|
|
```
|
|
|
|
|
|
|
|
Averaging execution time over multiple runs:
|
|
|
|
|
|
|
|
```ts
|
|
|
|
bench({
|
|
|
|
name: "runs100ForIncrementX1e6",
|
|
|
|
runs: 100,
|
|
|
|
func(b) {
|
|
|
|
b.start();
|
|
|
|
for (let i = 0; i < 1e6; i++);
|
|
|
|
b.stop();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Benching API
|
|
|
|
|
|
|
|
##### `bench(benchmark: BenchmarkDefinition | BenchmarkFunction): void`
|
|
|
|
|
|
|
|
Registers a benchmark that will be run once `runBenchmarks` is called.
|
|
|
|
|
|
|
|
##### `runBenchmarks(opts?: BenchmarkRunOptions): Promise<void>`
|
|
|
|
|
|
|
|
Runs all registered benchmarks serially. Filtering can be applied by setting
|
|
|
|
`BenchmarkRunOptions.only` and/or `BenchmarkRunOptions.skip` to regular expressions matching benchmark names.
|
|
|
|
|
|
|
|
##### `runIfMain(meta: ImportMeta, opts?: BenchmarkRunOptions): Promise<void>`
|
|
|
|
|
|
|
|
Runs specified benchmarks if the enclosing script is main.
|
|
|
|
|
|
|
|
##### Other exports
|
|
|
|
|
|
|
|
```ts
|
|
|
|
/** Provides methods for starting and stopping a benchmark clock. */
|
|
|
|
export interface BenchmarkTimer {
|
|
|
|
start: () => void;
|
|
|
|
stop: () => void;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Defines a benchmark through a named function. */
|
|
|
|
export interface BenchmarkFunction {
|
|
|
|
(b: BenchmarkTimer): void | Promise<void>;
|
|
|
|
name: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Defines a benchmark definition with configurable runs. */
|
|
|
|
export interface BenchmarkDefinition {
|
|
|
|
func: BenchmarkFunction;
|
|
|
|
name: string;
|
|
|
|
runs?: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Defines runBenchmark's run constraints by matching benchmark names. */
|
|
|
|
export interface BenchmarkRunOptions {
|
|
|
|
only?: RegExp;
|
|
|
|
skip?: RegExp;
|
|
|
|
}
|
|
|
|
```
|