メモ：node.jsのjestでユニットテスト

[pythonのユニットテストpytest](https://qiita.com/DiveMasakazu/items/b242e92ab4aca99c6877)は軽く見たので、node.jsも見ておく。
現時点だとjestというのが一番良さそう。
[公式日本語版}(https://jestjs.io/ja/docs/getting-started)ぽいのや
[ここ](https://qiita.com/rnasahiro/items/2d6584a915745218442e)、[ここ](https://webbibouroku.com/Blog/Article/typescript-jest)
を確認しながら。

#インストール
単体だと`npm install jest`だが
`npm install typescript jest @types/jest ts-jest`で入れた。
実際の開発現場だと`--save-dev`してるのかも
27.4.5で入った。

`jest -init`コマンドを流すのだが

```
C:\nodejs\jest>.\node_modules\.bin\jest --init
Could not find a "package.json" file in C:\nodejs\jest
```

とpackage.jsonがないとエラーになるようなので

```json:package.json
{
  "scripts": {
    "test": "jest"
  }
}
```
を作成してから実行、y/nの選択肢が出てくるがエンター連打で良さそう。

# 実行テスト
適当なtarget.jsを作成してテストしてみる。
exportで出力する形の.js（もしくは.ts）をテストするのが基本のようなので公式に倣う。

中身は公式のスクリプトとほぼ同じもの。

```javascript:target.js
function sum(a, b) {
    return a + b;
  }
module.exports = sum;
```

テストは`__tests__`フォルダを作成して、target.test.jsを作成
特に設定をしない場合、jestは自動的に__tests__以下からxxxx.test.jsを見つける。

```javascript:target.test.js
const sum = require('../target');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
```

これで`npm test`を実行する事で`Tests: 1 passed, 1 total`が出たのでOK

# 実際の使い方
## 比較式
`expect(実行).toBe(答え)`
で基本的な関数のテストは行う事が可能。
この時`===`で比較するので注意。値比較で良いなら`.toEqual`も使える。
○○以外ではない事を確認する事は少なそうだが、`expect(x).not.toBe(y)`を使う。
その他`toBeNull,toBeTruthy,toBeFalsy`などが使える。
文字列は`toMatch`で正規表現比較が可能。配列にはtoContain。
javascriptの正規表現は[ここ](https://qiita.com/iLLviA/items/b6bf680cd2408edd050f)等で。

小数の比較の場合は丸め誤差(0.1+0.2と0.3の比較など)が影響するので
`toBeCloseTo`を使うと無視できる。

例外が出るかどうかについては
`expect(() => compileAndroidCode()).toThrow();`
のようにラムダ式＋toThrowで判定

プロパティを見るにはtoHaveProperty

この辺りが主な判定方法で、全てを確認する場合は[ドキュメント](https://jestjs.io/ja/docs/expect)を見る。

## 非同期
非同期系のコードをテストする場合の情報は[ここ](https://jestjs.io/ja/docs/asynchronous)を参照。
Async/Awaitを確認。
jsonはhttp://jsonplaceholder.typicode.com/postsにアクセスして取得する。
node.jsのrequestが非推奨になっているので代わりに`npm install axios`。
プロキシはオプションで設定する。

```javascript:target.js
const { assertJSXAttribute } = require("@babel/types");
const axios = require("axios");

const proxyConfig = { proxy: { host: 'hostname', port: '8080' } }

function sum(a, b) {
    return a + b;
  }

async function  getjson(n){
    return await axios.get("http://jsonplaceholder.typicode.com/posts/"+n ,proxyConfig );
}

 module.exports = getjson;
```

テスト側でも普通にasync,awaitを使う。

```javascript:target.test.js
const getjson = require('../target');


test('json', async () => {
  const res = await getjson(3)
  expect(res.data.id).toBe(3);
});
```

## 事前処理

beforeとafterを利用する

```javascript
beforeEach(() => {
  initializeDatabase();
});

afterEach(() => {
  clearDatabase();
});
```

## モック
[公式](https://jestjs.io/ja/docs/27.0/mock-functions)の他
実装については[ここ](https://qiita.com/souhei-etou/items/3b93b529137c21563a0f)や[ここ](https://zenn.dev/kojiroueda/articles/ad28c45bb44b2e)考え方含めては[ここ](https://qiita.com/s_karuta/items/ee211251d944e72b2517)とかが参考になるかも？


関数の場合はjest.fnを利用する。

```javascript
const mockCallback = jest.fn(x => 42 + x);
const mockFunc = jest.fn().mockImplementation(() => "mock func");
```

のようにする。

ライブラリの場合は

```javascript
jest.mock("random"); // jest.mockでモックを使う宣言をして

test('should fetch users', () => {
  const users = [{name: 'Bob'}];
  const resp = {data: users};
  axios.get.mockResolvedValue(resp); // getをCallした時にmockが返す値をセット

  // もしくはmockImplementation
  // or you could use the following depending on your use case:
  // axios.get.mockImplementation(() => Promise.resolve(resp))

  // Usersクラスのstaticなallをチェック
  return Users.all().then(data => expect(data).toEqual(users));
});
```

基本はなんとなくわかった気になった。