いろんなJavaScriptのテストフレームワークを試してみる！

[Ateam Brides Inc. Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ateam-brides)の9日目は
株式会社エイチームブライズの@oekazumaが担当します。

# はじめに
今回試すJavaScriptのテストフレームワークは[Jest](https://github.com/facebook/jest)、[AVA](https://github.com/avajs/ava)、[Mocha](https://github.com/mochajs/mocha)、[tape](https://github.com/substack/tape)、[Jasmine](https://github.com/jasmine/jasmine)、[uvu](https://github.com/lukeed/uvu)です。

今回使用したコードはこちら
https://github.com/oekazuma/test-runner-compare

テストするコードは簡単な計算をするプログラムを用意しました。

```js:math.js
exports.sum = (a, b) => a + b;
exports.div = (a, b) => a / b;
exports.mod = (a, b) => a % b;
```


# [Jest](https://github.com/facebook/jest)

## インストール

```bash
$ npm install --save-dev jest
```

## テストコード

```js
const math = require('../math');

describe('sum', () => {
	it('should be a function', () => {
		expect(typeof math.sum).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.sum(1, 2)).toBe(3);
		expect(math.sum(-1, -2)).toBe(-3);
		expect(math.sum(-1, 1)).toBe(0);
	});
});

describe('div', () => {
	it('should be a function', () => {
		expect(typeof math.div).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.div(1, 2)).toBe(0.5);
		expect(math.div(-1, -2)).toBe(0.5);
		expect(math.div(-1, 1)).toBe(-1);
	});
});

describe('mod', () => {
	it('should be a function', () => {
		expect(typeof math.mod).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.mod(1, 2)).toBe(1);
		expect(math.mod(-3, -2)).toBe(-1);
		expect(math.mod(7, 4)).toBe(3);
	});
});
```

## 実行結果

```bash
> jest

 PASS  ./index.spec.js
  sum
    ✓ should be a function (1 ms)
    ✓ should compute values correctly
  div
    ✓ should be a function
    ✓ should compute values correctly (1 ms)
  mod
    ✓ should be a function
    ✓ should compute values correctly (1 ms)

Test Suites: 1 passed, 1 total
Tests:       6 passed, 6 total
Snapshots:   0 total
Time:        0.274 s, estimated 1 s
Ran all test suites.
```

# [AVA](https://github.com/avajs/ava)

## インストール

```bash
$ npm install --save-dev ava
```

## テストコード

```js
const test = require('ava');
const math = require('../math');

test('sum', t => {
	t.is(typeof math.sum, 'function');
	t.is(math.sum(1, 2), 3);
	t.is(math.sum(-1, -2), -3);
	t.is(math.sum(-1, 1), 0);
});

test('div', t => {
	t.is(typeof math.div, 'function');
	t.is(math.div(1, 2), 0.5);
	t.is(math.div(-1, -2), 0.5);
	t.is(math.div(-1, 1), -1);
});

test('mod', t => {
	t.is(typeof math.mod, 'function');
	t.is(math.mod(1, 2), 1);
	t.is(math.mod(-3, -2), -1);
	t.is(math.mod(7, 4), 3);
});
```

## 実行結果

```bash
> ava

  ✔ sum
  ✔ div
  ✔ mod
  ─

  3 tests passed
```

# [Mocha](https://github.com/mochajs/mocha)
## インストール

```bash
$ npm install --save-dev mocha
```

## テストコード

```js
const assert = require('assert');
const math = require('../math');

describe('sum', () => {
	it('should be a function', () => {
		assert.equal(typeof math.sum, 'function');
	});

	it('should compute result correctly', () => {
		assert.equal(math.sum(1, 2), 3);
		assert.equal(math.sum(-1, -2), -3);
		assert.equal(math.sum(-1, 1), 0);
	});
});

describe('div', () => {
	it('should be a function', () => {
		assert.equal(typeof math.div, 'function');
	});

	it('should compute result correctly', () => {
		assert.equal(math.div(1, 2), 0.5);
		assert.equal(math.div(-1, -2), 0.5);
		assert.equal(math.div(-1, 1), -1);
	});
});

describe('mod', () => {
	it('should be a function', () => {
		assert.equal(typeof math.mod, 'function');
	});

	it('should compute result correctly', () => {
		assert.equal(math.mod(1, 2), 1);
		assert.equal(math.mod(-3, -2), -1);
		assert.equal(math.mod(7, 4), 3);
	});
});
```

## 実行結果

```bash
> mocha

  sum
    ✔ should be a function
    ✔ should compute result correctly

  div
    ✔ should be a function
    ✔ should compute result correctly

  mod
    ✔ should be a function
    ✔ should compute result correctly


  6 passing (7ms)
```

# [tape](https://github.com/substack/tape)

## インストール

```bash
$ npm install --save-dev tape
```

## テストコード

```js
const test = require('tape');
const math = require('../math');

test('sum', t => {
	t.is(typeof math.sum, 'function');
	t.is(math.sum(1, 2), 3);
	t.is(math.sum(-1, -2), -3);
	t.is(math.sum(-1, 1), 0);
	t.end();
});

test('div', t => {
	t.is(typeof math.div, 'function');
	t.is(math.div(1, 2), 0.5);
	t.is(math.div(-1, -2), 0.5);
	t.is(math.div(-1, 1), -1);
	t.end();
});

test('mod', t => {
	t.is(typeof math.mod, 'function');
	t.is(math.mod(1, 2), 1);
	t.is(math.mod(-3, -2), -1);
	t.is(math.mod(7, 4), 3);
	t.end();
});
```

## 実行結果

```bash
> tape

TAP version 13
# sum
ok 1 should be strictly equal
ok 2 should be strictly equal
ok 3 should be strictly equal
ok 4 should be strictly equal
# div
ok 5 should be strictly equal
ok 6 should be strictly equal
ok 7 should be strictly equal
ok 8 should be strictly equal
# mod
ok 9 should be strictly equal
ok 10 should be strictly equal
ok 11 should be strictly equal
ok 12 should be strictly equal

1..12
# tests 12
# pass  12

# ok
```

# [Jasmine](https://github.com/jasmine/jasmine)
## インストール

```bash
$ npm install --save-dev jasmine
```

## テストコード

```js
const math = require('../math');

describe('sum', () => {
	it('should be a function', () => {
		expect(typeof math.sum).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.sum(1, 2)).toBe(3);
		expect(math.sum(-1, -2)).toBe(-3);
		expect(math.sum(-1, 1)).toBe(0);
	});
});

describe('div', () => {
	it('should be a function', () => {
		expect(typeof math.div).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.div(1, 2)).toBe(0.5);
		expect(math.div(-1, -2)).toBe(0.5);
		expect(math.div(-1, 1)).toBe(-1);
	});
});

describe('mod', () => {
	it('should be a function', () => {
		expect(typeof math.mod).toBe('function');
	});

	it('should compute values correctly', () => {
		expect(math.mod(1, 2)).toBe(1);
		expect(math.mod(-3, -2)).toBe(-1);
		expect(math.mod(7, 4)).toBe(3);
	});
});
```

## 実行結果

```bash
> jasmine

Randomized with seed 53426
Started
......


6 specs, 0 failures
Finished in 0.011 seconds
Randomized with seed 53426 (jasmine --random=true --seed=53426)
```

# [uvu](https://github.com/lukeed/uvu)

## インストール

```bash
$ npm install --save-dev uvu
```

## テストコード

```js
const { test } = require('uvu');
const assert = require('uvu/assert');
const math = require('../math');

test('sum', () => {
	assert.type(math.sum, 'function');
	assert.is(math.sum(1, 2), 3);
	assert.is(math.sum(-1, -2), -3);
	assert.is(math.sum(-1, 1), 0);
});

test('div', () => {
	assert.type(math.div, 'function');
	assert.is(math.div(1, 2), 0.5);
	assert.is(math.div(-1, -2), 0.5);
	assert.is(math.div(-1, 1), -1);
});

test('mod', () => {
	assert.type(math.mod, 'function');
	assert.is(math.mod(1, 2), 1);
	assert.is(math.mod(-3, -2), -1);
	assert.is(math.mod(7, 4), 3);
});

test.run();
```

## 実行結果

```bash
> uvu

index.js
• • •   (3 / 3)

  Total:     3
  Passed:    3
  Skipped:   0
  Duration:  1.01ms
```

# ベンチマーク

```bash
~> "jest" 1.02s
~> "ava" 564ms
~> "mocha" 194ms
~> "tape" 118ms
~> "jasmine" 96ms
~> "uvu" 87ms
```

# [State of JavaScript](https://2020.stateofjs.com/ja-JP/technologies/testing/)

![state of javascript](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/3914c68b-a13c-9b2d-6081-a711f67aaa64.png)

State of JavaScriptを見るとJestがダントツ人気で、次にMocha、Jasmine、AVAといったかんじですね。
やっぱりJestは強いです！

# [npm trends](https://www.npmtrends.com/ava-vs-jasmine-vs-jest-vs-mocha-vs-tape-vs-uvu)
![npm trends](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217487/e58c14e1-7db4-bbd8-d311-bb47f6bd24d7.png)

ダウンロード数を半年で比較すると概ね、State of JacaScriptと同じような結果になりました。

# JavaScriptフレームワーク
JavaScriptフレームワークの開発で使用されているテストフレームワークも調べてみました。

## [React](https://github.com/facebook/react)
Jest

## [Vue](https://github.com/vuejs/vue)
Jasmine

## [Angular](https://github.com/angular/angular)
Jasmine

## [Svelte](https://github.com/sveltejs/svelte)
Mocha

## [Next.js](https://github.com/vercel/next.js/)
Jest

## [Nuxt.js 2](https://github.com/nuxt/nuxt.js)
Jest

## [Nuxt.js 3](https://github.com/nuxt/framework)
Mocha

## [SvelteKit](https://github.com/sveltejs/kit)
uvu

# おわりに
今回は主要なJavaScriptのテストフレームワークを6つ試してみました！
それぞれ書き方や、実行結果の表示の仕方や、速度に違いがあり、おもしろいなと思いました。
JavaScriptフレームワークの開発で使用されているテストフレームワークがそれぞれバラバラなのも興味深いです。
Jestはもちろんのこと、JasmineとMochaも使われてるケースがあり、一番後発であるSvelteKitはuvuが使われています。
uvuはベンチマークを見る限りでは一番早くて、軽量ですので今後注目です！
内包している機能が違うので単純比較できないかもしれませんが、Jestは実行速度が遅くなってしまう印象なので実行速度を早めたい場合はJest以外のテストフレームワークを使ってみるのもいいかもしれません。