TypescriptとJestで単体テストをやってみる

MacでTypescriptでJestで実装から単体テストまでやってみたのでまとめておこうと思います。

## Node.js
まず、大前提としてNode.jsが必要となります。javascriptの実行環境です。
### インストール
[公式](https://nodejs.org/ja/)にはダウンローダのダウンロードがありましたが、Homebrewで入れられるそうなので、そっちから入れます。
#### 1. まず、Node.jsのバージョン管理ツールをインストール

```bash
$ brew install nodebrew
$ nodebrew -v # nodebrew 1.0.1 {使い方とか...}
```
#### 2. Node.jsのインストール

```bash
$ nodebrew ls-remote # インストールできるバージョンを確認
$ nodebrew install-binary stable # このstable(安定版)の箇所はバージョンまたはlatest(最新版)でもOK
```
私の環境ではここで"No such file or directory"が出ました。
その時には

```bash
$ mkdir -p ~/.nodebrew/src
```
を実行して再度上記のインストールを実行してみて下さい。

```bash
$ nodebrew ls # インストールされているバージョンを確認
$ nodebrew use v14.5.0 # 私の時はstableはこのバージョンでした、時期にはよると思うので、インストールされているバージョンを入れて下さい。
```
~/.bash_profileに

```bash
export PATH=$HOME/.nodebrew/current/bin:$PATH
```
を追記してパスを追加し、

```bash
source ~/.bash_profile
```
で反映して下さい。

```bash
$ node -v
```
でバージョンが表示されればインストール成功です。

## Typescript
[公式チュートリアル](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)を参照してます
型のついたjavascriptで、typescriptを書いて、それをjavascriptにコンパイルして利用します。
本当にただコンパイルしてjavascriptを吐いてくれるだけなので、導入がめちゃんこ楽でした。

### インストール
Node.jsについてくるnpmでインストールします。

```bash
$ npm i -g typescript
```

### コンパイル
Typescript動作を試してみましょう。

```bash
$ mkdir temp; cd temp # 適当なディレクトリに作成
```
挙動確認ようにindex.htmlを作っておきます。内容はこんな感じです。

```html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <script src="temp.js"></script>
    </body>
</html>
```
以下の内容のtemp.tsというTypescriptファイルを作成

```ts
function temp(num){
    return "カウントは" + num.toString() + "です。";
}

document.body.textContent = temp(2); // カウントは2です。
```
これみるとわかると思いますが、完全にjavascriptです。これだけみるとTypescriptってなんぞ？ってなってしまいます。
因みにちゃんとTypescriptっぽく型をつけてあげるとこうなります。

```ts
function temp(num: number): string{
    return "カウントは" + num.toString() + "です。";
}

document.body.textContent = temp(2); // カウントは2です。
```
上記どちらのtemp.tsにおいてもコンパイルして出力されるtemp.jsファイルの内容は同様のものとなります。
このtempに対して文字列を渡してあげるとエラーとなります。

```ts
temp("test"); // エラー: tempの引数の型numberに対して、”test”の型は代入できないよ
```
javascriptならば許された記述(実際、最初に書いたtemp.tsならこれでも通るし動きます。)ですが、Typescriptで型を指定すると許されません。

## Jest
javascriptのテストフレームワークです。

### インストール
開発用のパッケージとしてインストールします。
基本的にテスト系のパッケージは開発用のパッケージとしてインストールすることになる思ってます。(利用する上では不要ですから。)

```bash
$ npm init -y
$ npm i -D jest
```
※npmコマンドの引数部分は以下のエイリアスとなってます。

- i: install
- -D: --save-dev

また、--save-devとか気になるようでしたら[ここのサイト](https://seinzumtode.hatenadiary.jp/entry/20160226/1456450867)が分かり易かったです。

### テストと設定の作成
temp.tsを以下のように修正(module.exportsの行を追加するだけです。テストモジュールからこのtemp関数を呼び出すために追加します。)

```ts
function temp(num: number): string{                              
    return "カウントは" + num.toString() + "です。";
}   
module.exports = temp; // この行を追加
document.body.textContent = temp(2); // カウントは2です。
```
修正したら、再びコンパイルです。

```bash
$ tsc temp.ts
```
package.jsonファイル内の"scripts"を変更します。多分今は"test"に"echo~"みたいなのが設定されていると思います。これを以下のように設定してください。この設定によってnpm testコマンドでjestが実行されるようになります。

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

### テスト実行
以下のコマンドを実行することでテストを実行することができます。

```bash
$ npm t
```
上記のpackage.json設定をしなくても以下のコマンドでテスト実行できますが、jest以外のフレームワークを使った際にもテスト方法が統一できるためこっちを使ってます。

```bash
$ npx jest
```

## JestでTypescriptをテスト
ここまででTypescriptとJestについての準備は済んだのでここからTypescriptをJestでテストします。
### ディレクトリ構造
また新しくディレクトリを作成していきます。最終的にはこんな感じのディレクトリ構造になる予定です。

```bash
tsc_test/
  ├src/
  │ ├temp.ts
  │ └__tests__/
  │   └temp.test.ts
  ├package.json
  └jest.config.js
```
まずはディレクトリを作成します。

```bash
$ mkdir -p tsc_jest/src/__tests__; cd tsc_jest
```

### テストのために必要となるパッケージやファイルの準備
まずはパッケージのインストールを行います。

```bash
$ npm init -y
$ npm i jest @types/jest ts-jest typescript -D
```

Jestの設定ファイルを作成します。以下の内容のjest.config.jsというファイルを作成して下さい。

```js
module.exports = {
  "roots": [
    "<rootDir>/src"
  ],
  "testMatch": [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)"
  ],
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest"
  },
}
```
また、先程と同様にpackage.jsonの"scripts"を以下のように変更して下さい。

```json
  "scripts": {
    "test": "jest"
  }
```
これでテストの設定ファイル等の準備は完了です。この状態でテストを実行すると

```bash
$ npm t
```
No tests found ~みたいなメッセージが出るはずです。まだテスト対象のモジュールもテストファイルも作っていないのでこのメッセージでOKです。

テスト対象のモジュールを作成します。
srcディレクトリ直下に以下の内容のtemp.tsファイルを作成して下さい。

```ts
export const sum
    = (...num: number[]): number => 
        num.reduce((acc, val) => acc + val, 0);
```

次にテストファイルを作成します。
src/__tests__ディレクトリ直下に以下の内容のtemp.test.tsファイルを作成して下さい。

```ts
import { sum } from "../temp";                                   

test("要素数0の場合", () => {
    expect(sum()).toBe(0);
}); 

test("要素数2の場合", () => {
    expect(sum(1, 2)).toBe(3);
});
```

### テストの実行
これで準備完了です。テストを実行してみましょう。

```bash
$ npm t
```

こんな画面が表示されていれば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/d4b7cc17-812c-c5e1-49f6-6c614386264c.png)

# まとめ
今回はTypescriptについて深く触れませんでしたが、javascriptなのでclassや匿名関数が使えてTypescriptではinterfaceやgenericsも使えます。単にjavascriptをそんなに触っていないというのもありますが、普段PythonでもTypeHintを書くので、型を指定できるっていうのはとても使い易いなぁって感じました。
今後フロントの開発ではTypescriptで書いていこうと思います。