【TypeScript】jestでユニットテストを行う【TypeScript Deep Dive全部読む】

## jestとは？

javascriptでユニットテストを行うためのフレームワーク。Facebook製のOSSであり、シンプルながら欲しい機能が一通り揃っている。

今回はこれをtypescriptで動かす。

参考: 

https://typescript-jp.gitbook.io/deep-dive/intro-1/jest

https://jestjs.io/ja/docs/getting-started

## 導入

#### npmを用いてインストールする

```
npm i jest @types/jest ts-jest -D
```

ここでjestはフレームワーク、@types/jestはjestの型情報、ts-jestはtypescript用のプリプロセッサである。


#### jest.config.jsの作成
以下の設定ファイルをプロジェクトのルートに配置する。
```js
module.exports = {
  preset: "ts-jest",
  testEnvironment: "node",
  testMatch: ["**/__tests__/**/*.test.ts"],
  collectCoverage: true,
}
```

ここでpresetはjest実行環境の指定。testEnvironmentは環境の設定で、デフォルトはNode.js環境となっている。testMatchはどのファイルを参照するかを正規表現で表す。collectCoverageはtrueに設定しておくとカバレッジ情報が見れて便利。

その他オプションは以下↓を参照する。

https://jestjs.io/ja/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object

### npm runで実行できるよう設定する

package.jsonに以下を追加する。

```json
  "scripts": {
    "test": "jest"
  }
```

## 実際にやってみよう

```src/sum.ts```として以下のファイルを作成する。単純に足し算をするだけの関数と、2倍にして返すだけの関数を作った。

```ts
export const sum = (a: number, b: number) => {
    return a + b;
}

export const double = (a: number) => {
    return a*2;
}
```

これをテストしてみる。まずtestMatchで指定したように、
```__tests__/sum.test.ts```というファイルを作成する。

```ts
import { sum, double } from "../src/sum";
```

これで作成した関数を読み込む。```it()```でテストしてみよう。なお```it()```と```test()```のどちらを使ってもよい。

```ts
it('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
```
```it(name, fn)```関数で実行し、中の```expect()```で行いたい計算を指定し、最後に```toBe()```といったマッチャーで求めた結果になっているか調べる。

マッチャーには```toBeNull```や```toBeGreaterThan()```といった種類がある。

https://jestjs.io/ja/docs/using-matchers

これを実行してみる。

```
npm run test
```
で実行。この場合はrunの省略もできる。
```
npm test
```
これで以下のような出力が得られた。

```
 PASS  __tests__/sum.test.ts
  √ adds 1 + 2 to equal 3 (3 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   83.33 |      100 |      50 |      75 | 
 sum.ts   |   83.33 |      100 |      50 |      75 | 6
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.87 s, estimated 3 s
Ran all test suites.
```
テストは成功。ただし二つある関数(sum, double)の一方しか動かしていないことがカバレッジ情報からわかる。

もう一方も動かしてみよう。同じように書いてもいいが、今度は複数ケースを作ってみる。

```ts
describe("double", () => {
  it("should return a*2", () => {
    const array = [1, 3, 5];
    array.forEach((a) => {
      expect(double(a)).toBe(a*2);
    });
  })
})
```
```describe(name, fn)```を用いることで複数のテストをグループにまとめて実行することができる。
```describe.each```や```it.each```等を使用することでまとめて行うこともできる。

同様に実行してみる。

```
 PASS  __tests__/sum.test.ts
  √ adds 1 + 2 to equal 3 (3 ms)
  double
    √ should return a*2 (2 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 | 
 sum.ts   |     100 |      100 |     100 |     100 | 
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        3.092 s
Ran all test suites.
```
これでテストが完了した。