Jestを使った関数のテストについて

## Jestを使った関数のテストについて

今回は、Jestを使用して関数をテストするサンプルプログラムについて、わかりやすく解説していきます。

下記はテスト元のサンプルプログラムになります
```javascript:(testes.js)

/**
 * 指定された郵便番号から住所を取得するためにAPIを呼び出します。
 * @param {string} zipcode - 検索する郵便番号（ハイフンなしの7桁）。
 * @returns {Promise} - APIからのレスポンスを含むPromiseオブジェクト。
 * @throws {Error} - 引数が空の文字列であるか、7桁の数字でない場合にエラーをスローします。
 */
function getZipCloud(zipcode) {
  if (!zipcode) {
    return Promise.reject(new Error("郵便番号を入力してください。"));
  } else if (!/^\d{7}$/.test(zipcode)) {
    return Promise.reject(
      new Error("郵便番号は7桁の数字である必要があります。")
    );
  } else {
    /**
     * 指定された郵便番号から住所を取得するためにAPIを呼び出すURL。
     * @type {string}
     */
    const url = `http://zipcloud.ibsnet.co.jp/api/search?zipcode=${zipcode}`;

    /**
     * fetch関数を使用してAPIを呼び出します。
     * @returns {Promise} - APIからのレスポンスを含むPromiseオブジェクト。
     * @throws {Error} - HTTPレスポンスがOKでない場合、またはJSONレスポンスの解析中にエラーが発生した場合にエラーをスローします。
     */
    return fetch(url)
      .then((res) => {
        if (!res.ok) {
          throw new Error(`HTTPエラー：${res.status}`);
        }
        return res.json();
      })
      .then((data) => {
        console.log(data);
        return data;
      })
      .catch((err) => {
        throw err;
      });
  }
}

/**
 * getZipCloud関数を呼び出して、結果をコンソールにログ出力します。
 */
getZipCloud("1000001")
  .then((result) => {
    console.log(result);
    console.log(result.results[0].address1);
  })
  .catch((err) => {
    console.error(err.message);
  });

/**
 * getZipCloud関数をエクスポートします。
 */
module.exports = {
  getZipCloud,
};

```




---

## Jestを使った`getZipCloud`関数のテストについて

### 前提

以下のコードは、`getZipCloud`関数をテストするためのJestのサンプルプログラムです。この関数は、郵便番号を引数として受け取り、何らかの処理を行うものとします。

```javascript
const { getZipCloud } = require("./testes");
```

### テストの概要

- **HTTPモジュールのモック化**
  Jestを使用してHTTPモジュールをモック化します。
- [モックについての詳しい解説はこちら](#補足モックに関する部分を詳しく解説
)

  ```javascript
  jest.mock("http");
  ```

- **`getZipCloud`関数のテストケースの記述**

  `describe`関数を使用して、`getZipCloud`関数のテストケースをグループ化します。

  ```javascript
  describe("getZipCloud", () => {
  ```

  1. **郵便番号が提供されなかった場合のテスト**

     関数に何も引数を渡さなかった場合、エラーメッセージ「郵便番号を入力してください。」が返されることを確認します。

     ```javascript
     it("should reject with an error if no zipcode is provided", async () => {
         await expect(getZipCloud()).rejects.toThrow("郵便番号を入力してください。");
     });
     ```

  2. **無効な郵便番号が提供された場合のテスト**

     無効な郵便番号（例: "123456"）を関数に渡した場合、エラーメッセージ「郵便番号は7桁の数字である必要があります。」が返されることを確認します。

     ```javascript
     it("should reject with an error if an invalid zipcode is provided", async () => {
         await expect(getZipCloud("123456")).rejects.toThrow("郵便番号は7桁の数字である必要があります。");
     });
     ```

  3. **有効な郵便番号が提供された場合のテスト**

     有効な郵便番号（例: "1000000"）を関数に渡した場合、期待されるデータ（この場合は"ああああ"）が返されることを確認します。

     ```javascript
     it("should resolve with the data from the API if a valid zipcode is provided", async () => {
         const mockData = { results: [{ address1: "ああああ" }] };
         const mockResponse = {
           ok: true,
           json: jest.fn().mockResolvedValue(mockData),
         };
         global.fetch = jest.fn().mockResolvedValue(mockResponse);
         const result = await getZipCloud("1000000");
         expect(result).toEqual("ああああ");
     });
     ```


  4. **APIがエラーを返した場合のテスト**

     APIからエラーが返された場合（例: ステータスコード500）、関数がそのエラーを正しく処理することを確認します。

     ```javascript
     it("should reject with an error if the API returns an error", async () => {
         const mockError = new Error("API error");
         const mockResponse = {
           ok: false,
           status: 500,
         };
         global.fetch = jest.fn().mockResolvedValue(mockResponse);
         await expect(getZipCloud("1234567")).rejects.toThrow(`HTTP error: ${mockResponse.status}`);
     });
     ```

---

以上が、Jestを使用して`getZipCloud`関数をテストするサンプルプログラムのマークダウン形式での説明でした。このサンプルを参考に、自身のコードのテストも行ってみてくださいね！

   
---
### 補足モックに関する部分を詳しく解説
---

### モック (Mocking) とは

モックはテストの際に実際のオブジェクトや関数の代わりに使用されるものです。モックを使用する主な理由は以下の通りです：

1. **外部の依存関係を排除する**：例えば、外部APIやデータベースへのアクセスを伴う関数をテストする場合、そのAPIやデータベースが常に利用可能であるとは限りません。モックを使用することで、これらの外部依存関係を模倣（モック化）して、テストを安定的に行うことができます。

2. **テストの速度を向上させる**：外部サービスへの実際のリクエストは時間がかかることがあります。モックを使用することで、リアルタイムの待機時間を排除し、テストの速度を向上させることができます。

3. **特定のシナリオをシミュレートする**：例えば、エラーシナリオや特定のレスポンスを返すシナリオなど、実際の環境では再現が難しいケースをモックを使用してシミュレートすることができます。

---

### サンプルプログラム内のモックについて

```javascript
// Mocks the http module
jest.mock("http");
```

上記のコードでは、`http`モジュールがモック化されています。これにより、`http`モジュールの実際の動作を行わず、Jestが提供するモック関数やオブジェクトを使用してテストを行うことができます。

また、以下の部分では`fetch`関数（外部APIへのリクエストを行う関数）がモック化されています。

```javascript
const mockResponse = {
  ok: true,
  json: jest.fn().mockResolvedValue(mockData),
};
global.fetch = jest.fn().mockResolvedValue(mockResponse);
```

このモックにより、`getZipCloud`関数が`fetch`関数を呼び出す際、実際のAPIリクエストを行う代わりにモックデータを返すようになります。これにより、APIの実際のレスポンスに依存せずに、関数の動作をテストすることができます。

---

モックは、テストの際に非常に有用なツールとなります。特に外部サービスやモジュールに依存する関数のテストを行う際には、モックを使用してテストの安定性や再現性を確保することが推奨されます。