|
1 | 1 | # Assemblyscript Unittest Framework
|
2 | 2 |
|
| 3 | +<div align="center"> |
| 4 | + <a href="https://deepwiki.com/wasm-ecosystem/assemblyscript-unittest-framework"> |
| 5 | + <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki" /> |
| 6 | + </a> |
| 7 | + <a href="https://www.npmjs.com/package/assemblyscript-unittest-framework"> |
| 8 | + <img src="https://img.shields.io/npm/v/assemblyscript-unittest-framework.svg?color=007acc&logo=npm" alt="npm" /> |
| 9 | + </a> |
| 10 | + <a href="https://discord.gg/assemblyscript"> |
| 11 | + <img |
| 12 | + src="https://img.shields.io/discord/721472913886281818.svg?label=discord&logo=discord&logoColor=ffffff&color=7389D8" |
| 13 | + alt="Discord online" |
| 14 | + /> |
| 15 | + </a> |
| 16 | +</div> |
| 17 | + |
3 | 18 | A comprehensive AssemblyScript testing solution, offering developers a robust suite of features to ensure their code performs as expected:
|
4 | 19 |
|
5 | 20 | - Function Mocking
|
6 | 21 | - Coverage statistics
|
7 | 22 | - Expectations
|
8 | 23 |
|
9 |
| -## Getting Started |
10 |
| - |
11 |
| -Install Assemblyscript Unittest Framework using npm |
12 |
| - |
13 |
| -```bash |
14 |
| -npm install --save-dev assemblyscript-unittest-framework |
15 |
| -``` |
16 |
| - |
17 |
| -Let's get started by writing a test for a simple function that add two numbers. Assume that there is already environment of assemblyscript. |
18 |
| - |
19 |
| -First, create `source/sum.ts`: |
20 |
| - |
21 |
| -```Typescript |
22 |
| -export function add(a: i32, b: i32): i32 { |
23 |
| - return a + b; |
24 |
| -} |
25 |
| -``` |
26 |
| - |
27 |
| -Then, create a file named `tests/sum.test.ts`. This will contain our actual test: |
28 |
| - |
29 |
| -```Typescript |
30 |
| -import { test, expect, endTest } from "assemblyscript-unittest-framework/assembly"; |
31 |
| -import { add } from "../source/sum"; |
32 |
| - |
33 |
| -test("sum", () => { |
34 |
| - expect(add(1, 2)).equal(3); |
35 |
| - expect(add(1, 1)).equal(3); |
36 |
| -}); |
37 |
| -endTest(); // Don't forget it! |
38 |
| -``` |
39 |
| - |
40 |
| -**Don't forget `endTest()` at the end of `*.test.ts` files** |
41 |
| - |
42 |
| -Create a config file in project root `as-test.config.js`: |
43 |
| - |
44 |
| -for cjs: |
45 |
| - |
46 |
| -```javascript |
47 |
| -module.exports = { |
48 |
| - include: ["source", "tests"], |
49 |
| -}; |
50 |
| -``` |
51 |
| - |
52 |
| -for mjs: |
53 |
| - |
54 |
| -```javascript |
55 |
| -export default { |
56 |
| - include: ["source", "tests"], |
57 |
| -}; |
58 |
| -``` |
59 |
| - |
60 |
| -Add the following section to your `package.json` |
61 |
| - |
62 |
| -```json |
63 |
| -{ |
64 |
| - "scripts": { |
65 |
| - "test": "as-test" |
66 |
| - } |
67 |
| -} |
68 |
| -``` |
69 |
| - |
70 |
| -Finally, run `npm run test` and as-test will print this message: |
71 |
| - |
72 |
| -``` |
73 |
| -transform source/sum.ts => build/source/sum.ts.cov |
74 |
| -transform build/source/sum.ts.cov => build/source/sum.ts |
75 |
| -transform tests/sum.test.ts => build/tests/sum.test.ts |
76 |
| -(node:489815) ExperimentalWarning: WASI is an experimental feature. This feature could change at any time |
77 |
| -
|
78 |
| -test case: 1/2 (success/total) |
79 |
| -
|
80 |
| -Error Message: |
81 |
| - sum: |
82 |
| - tests/sum.test.ts:6:3 (6:3, 6:29) |
83 |
| -``` |
84 |
| - |
85 |
| -You can also use `npx as-test -h` for more information to control detail configurations |
86 |
| - |
87 |
| -## Configuration |
88 |
| - |
89 |
| -This is the template of `as-test.config.js`: |
90 |
| - |
91 |
| -```javascript |
92 |
| -module.exports = { |
93 |
| - // test related code folder |
94 |
| - include: ["source", "tests"], |
95 |
| - exclude: [], |
96 |
| - |
97 |
| - /** optional: assemblyscript compile flag, default is --exportStart _start -O0 */ |
98 |
| - flags: "", |
99 |
| - |
100 |
| - /** |
101 |
| - * optional: import functions |
102 |
| - * @param {ImportsArgument} runtime |
103 |
| - * @returns |
104 |
| - */ |
105 |
| - imports(runtime) { |
106 |
| - return { |
107 |
| - env: { |
108 |
| - logInfo(ptr, len) { |
109 |
| - if (runtime.exports) { |
110 |
| - let arrbuf = runtime.exports.__getArrayBuffer(ptr); |
111 |
| - let str = Buffer.from(arrbuf).toString("utf8"); |
112 |
| - console.log(str); |
113 |
| - } |
114 |
| - }, |
115 |
| - }, |
116 |
| - builtin: { |
117 |
| - getU8FromLinkedMemory(a) { |
118 |
| - return 1; |
119 |
| - }, |
120 |
| - }, |
121 |
| - }; |
122 |
| - }, |
123 |
| - |
124 |
| - /** optional: template file path, default "coverage" */ |
125 |
| - // temp: "coverage", |
126 |
| - |
127 |
| - /** optional: report file path, default "coverage" */ |
128 |
| - // output: "coverage", |
129 |
| - |
130 |
| - /** optional: test result output format, default "table" */ |
131 |
| - // mode: ["html", "json", "table"], |
132 |
| -}; |
133 |
| - |
134 |
| -``` |
135 |
| - |
136 |
| -## Using Matchers |
137 |
| - |
138 |
| -The simplest way to test a value is with exact equality. |
139 |
| - |
140 |
| -```typescript |
141 |
| -test('two plus two is four', () => { |
142 |
| - expect(2 + 2).equal(4); |
143 |
| -}); |
144 |
| -``` |
145 |
| - |
146 |
| -In this code, `expect(2+2)` returns an "Value" object. You typically won't do much with these objects except call matchers on them. In this code, `.equal(4)` is the matcher. When Jest runs, it tracks all the failing matchers so that it can print out nice error messages for you. |
147 |
| - |
148 |
| -### Equal |
149 |
| - |
150 |
| -In the most condition, `equal` is similar as `==`, you can use this matcher to compare `i32 | i64 | u32 | u64 | f32 | f64 | string` just like `==`. What's more, it can also be used to compare some inner type, such as `Array | Map | Set`. |
151 |
| - |
152 |
| -However, **Class** and **Interface** cannot be compared directly now. |
153 |
| - |
154 |
| -`notEqual` is the opposite of `equal` |
155 |
| - |
156 |
| -### Numbers |
157 |
| - |
158 |
| -Most ways of comparing numbers have matcher equivalents, like `equal`, `greaterThan`, `greaterThanOrEqual`, `lessThan`, `lessThanOrEqual`. |
159 |
| - |
160 |
| -Specially, for float type, use `closeTo` instead of `equal` to avoid rounding error. |
161 |
| - |
162 |
| -## Nullable |
163 |
| - |
164 |
| -`isNull` and `notNull` matcher can be used to a nullable object. |
165 |
| -Of cource, you can also use `equal` and `notEqual` to do same thing with explicit generic declartion `expect<T | null>()` |
166 |
| - |
167 |
| -## Using Mock Function |
168 |
| - |
169 |
| -Because Assemblyscript's grammar is not as flexible as javascript, mock function have a lot of limitation and API design is not similar as jest (a javascript test framework). |
170 |
| - |
171 |
| -However, There is a way to do some mock function. |
172 |
| - |
173 |
| -Imagine that we are testing a function which includes a system-interface: |
174 |
| - |
175 |
| -```typescript |
176 |
| -// source.ts |
177 |
| -declare function sys_getTime(): i32; |
178 |
| -export function getTime(): bool { |
179 |
| - let errno = sys_getTime(); |
180 |
| - if (errno < 0) { |
181 |
| - // error handle |
182 |
| - return false; |
183 |
| - } |
184 |
| - // do something |
185 |
| - return true; |
186 |
| -} |
187 |
| -``` |
188 |
| - |
189 |
| -To test error handle part, we need to inject some code to `sys_getTime` and expect to return a errno. |
190 |
| - |
191 |
| -```typescript |
192 |
| -// source.test.ts |
193 |
| -test("getTime error handle", () => { |
194 |
| - const fn = mock(sys_getTime, () => { |
195 |
| - return -1; |
196 |
| - }); |
197 |
| - expect(getTime()).equal(false); // success |
198 |
| - expect(fn.calls).equal(1); // success |
199 |
| -}); |
200 |
| -endTest(); |
201 |
| -``` |
202 |
| - |
203 |
| -mock API can temporary change the behavior of function, effective scope is each test. |
204 |
| -In this mock function, you can do every thing include expecting arguments, mock return values and so on. |
205 |
| - |
206 |
| -Tips: |
207 |
| - |
208 |
| -- Because Assemblyscript is a strongly typed language, you should keep the function signature aligned. |
209 |
| -- AssemblyScript does not support closures. If a mock function needs to be called several times in one test, and you want it to return different values or match arguments to different values, using a global counter for this function is a good way to achieve this. |
210 |
| - |
211 |
| -### Example for MockFn |
212 |
| - |
213 |
| -1. expect arguments |
214 |
| - |
215 |
| - ```typescript |
216 |
| - test("check argument", () => { |
217 |
| - const fn = mock(add, (a: i32, b: i32) => { |
218 |
| - expect(a).equal(1); |
219 |
| - return a + b; |
220 |
| - }); |
221 |
| - expect(fn.calls).greaterThanOrEqual(1); |
222 |
| - }); |
223 |
| - ``` |
224 |
| - |
225 |
| -2. return difference value |
226 |
| - |
227 |
| - ```typescript |
228 |
| - const ret = [1,2,3,4,5,6,7,8]; // global variant |
229 |
| - const calls = 0; // global variant |
230 |
| - test("check argument", () => { |
231 |
| - const fn = mock(add, (a: i32, b: i32) => { |
232 |
| - return ret[calls++]; |
233 |
| - }); |
234 |
| - expect(fn.calls).greaterThanOrEqual(1); |
235 |
| - }); |
236 |
| - ``` |
237 |
| - |
238 |
| -3. re-call origin |
239 |
| - |
240 |
| - ```typescript |
241 |
| - test("call origin", () => { |
242 |
| - mock(add, (a: i32, b: i32) => { |
243 |
| - unmock(add); |
244 |
| - const res = add(a,b); |
245 |
| - remock(add); |
246 |
| - return res; |
247 |
| - }); |
248 |
| - }); |
249 |
| - ``` |
250 |
| - |
251 |
| -## Coverage Report |
252 |
| - |
253 |
| -After testing, you can get a html / json / table format test coverage report include "Statements Coverage", "Branches Coverage", "Functions Coverage", "Lines Coverage" |
| 24 | +Documentation: https://wasm-ecosystem.github.io/assemblyscript-unittest-framework/ |
254 | 25 |
|
255 | 26 | ## Architecture
|
256 | 27 |
|
|
0 commit comments