📝

【Google Maps API】VitestでGoogle Maps APIを用いた処理のテストコードを書こう

2024/07/01に公開

この記事について

以前、「【Google Maps API】 @googlemaps/jest-mocksを使ってテストコードを書こう」という記事を書きました。これはJestを使って、Google Maps APIのテストを書こうというものです

https://zenn.dev/p238049y/articles/a03f143ae77e00

今回はVitestバージョンです。Vitestを使って、Google Maps APIを書いていきます

https://vitest.dev/

先に結論を3つ

  • VitestとはBlazing Fast Unit Test Frameworkとドキュメントに記載されている通り、とんでもなく早いユニットテストフレームワークのこと
  • @googlemaps/jest-mocksは使えないので、@soleo/google-maps-vitest-mocksを使ってテストをしました
  • Jest版と同様に書くことが可能

Vitest とは

VitestとはBlazing Fast Unit Test Frameworkとドキュメントに記載されている通り、とんでもなく早いユニットテストフレームワークのことです。
説明は「Viteを利用したテストツールVitestの利用を始める」という記事に委ねます。わかりやすくまとめられていると思ったためです。VitestはJestと同じような記法で記載が可能です。

https://qiita.com/KokiSakano/items/f23e979004f72d70165e

@soleo/google-maps-vitest-mocksとは

@soleo/google-maps-vitest-mocksはVitestにおいてGoogle Mapをモックしてくれるライブラリです。

これを使わずに@googlemaps/jest-mocksを使ってテストを実行してみたのですが、以下の結果の通り実行できませんでした。。。

❯❯❯ npx vitest run -t "編集可能かどうかを判定するメソッドの戻り値がtrueであること"

 RUN  v1.6.0 /test/models

 ❯ CustomPolyline.test.ts (0)

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Suites 1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

 FAIL  CustomPolyline.test.ts [ CustomPolyline.test.ts ]
ReferenceError: jest is not defined
 ❯ Object.<anonymous> ../../../node_modules/@googlemaps/jest-mocks/src/import-library.ts:1:30

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/1]⎯

 Test Files  1 failed (1)
      Tests  no tests
   Start at  21:09:11
   Duration  452ms (transform 63ms, setup 0ms, collect 0ms, tests 0ms, environment 101ms, prepare 55ms)

@soleo/google-maps-vitest-mocksを使ってテストを書き、実行すると以下の結果が得られます

❯❯❯ npx vitest run -t "編集可能かどうかを判定するメソッドの戻り値がtrueであること"

 RUN  v1.6.0 /test/models

 ✓ CustomPolyline.test.ts (4)
   ✓ CustomPolylineを編集可能かどうかを判定するメソッドであるisEditableのテスト (4)
     ✓ 編集者と作成者が同じの場合 (1)
       ✓ 編集可能かどうかを判定するメソッドの戻り値がtrueであること
     ↓ 編集者と作成者が同じでない場合 (1) [skipped]
       ↓ 編集可能かどうかを判定するメソッドの戻り値がfalseであること [skipped]
     ✓ 操作者が管理者の場合 (2)
       ✓ 編集者と作成者が同じの場合、編集可能かどうかを判定するメソッドの戻り値がtrueであること
       ✓ 編集者と作成者が同じでない場合、編集可能かどうかを判定するメソッドの戻り値がtrueであること

 Test Files  1 passed (1)
      Tests  3 passed | 1 skipped (4)
   Start at  21:10:50
   Duration  445ms (transform 61ms, setup 0ms, collect 66ms, tests 3ms, environment 105ms, prepare 50ms)

実際に試してみましょう

今回もcustomizePolylineというクラスのテストを実行したいと仮定します。isEditableというメソッドが意図した値を返してくれるかというテストをしたいと思います。

Polyline って何?

Google map上に書く線のことです。 (赤い矢印で示しているもの)
カスタマイズによっては、矢印のように書いたり、色や太さを変更させることができます。

以下で遊ぶことができます。

準備

仕様は以下の通りです。

  • 自分の作成したポリラインは編集可能
  • 自分以外が作成したポリラインが編集不可
  • 管理者の場合は自分、自分以外関係なく編集可能

これらの仕様を満たすクラスとメソッドを定義します。

// CustomPolyline.ts

export class CustomPolyline {
    id: string;
    polyline: google.maps.Polyline;
    colorCode: string;
    isOwnPolyline: boolean;
    createdId: number;

    constructor(
        id: string,
        polyline: google.maps.Polyline,
        colorCode: string,
        createdId: number,
        operatorUserId: number
    ) {
        this.id = id;
        this.polyline = polyline;
        this.colorCode = colorCode;
        this.isOwnPolyline = operatorUserId === createdId;
        this.createdId = createdId;
    }

    isEditable(hasAdminRole: boolean): boolean {
        if (hasAdminRole) {
            return true;
        } else {
            return this.isOwnPolyline;
        }
    }
}

テストを書いてみる

// CustomPolyline.test.ts

import { it, describe, expect } from "vitest";
import { useGoogleMapSetUp } from "../../config/map";
import { CustomPolyline } from "../../shared/models/CustomPolyline";
import { initialize, mockInstances, Polyline } from "@soleo/google-maps-vitest-mocks";


const { mapCommonOption } = useGoogleMapSetUp()

const initialPolyline = () => {
    const map = new google.maps.Map(document.createElement('div'));
    const polyline = new google.maps.Polyline({
      path: [
        new google.maps.LatLng({ lat: 34.40882247741932, lng: 136.6821998287318 }),
        new google.maps.LatLng({ lat: 34.40882247741933, lng: 136.6821998287319 }),
      ],
      ...mapCommonOption,
    });
    polyline.setMap(map);
  };

describe('CustomPolylineを編集可能かどうかを判定するメソッドであるisEditableのテスト', () => {
    initialize();
    initialPolyline();

    const mockPolylineList = mockInstances.get(Polyline);

    describe('編集者と作成者が同じの場合', () => {
        const hasAdminRole = false;

        const customizePolyline = new CustomPolyline(
            '01HY05BFHVNKRT3KSEP440Q845',
            mockPolylineList[0],
            '#ffffff',
            1,
            1
        );

        it('編集可能かどうかを判定するメソッドの戻り値がtrueであること', () => {
            expect(customizePolyline.isEditable(hasAdminRole)).toBe(true);
        })
    }),

    describe('編集者と作成者が同じでない場合', () => {
        // 省略
    }),

    describe('操作者が管理者の場合', () => {
        // 省略
    })
})

実行結果

❯❯❯ yarn test
yarn run v1.22.22
$ vitest

 DEV  v1.6.0 /vitest-try

 ✓ src/shared/models/CustomPolyline.ts (4)
 ✓ src/test/models/CustomPolyline.test.ts (4)
 ✓ src/test/components/HelloWorld.spec.ts (1) // 既存のテストが残っているだけなので無視してください

 Test Files  3 passed (3)
      Tests  9 passed (9)
   Start at  01:26:20
   Duration  507ms (transform 203ms, setup 0ms, collect 309ms, tests 22ms, environment 330ms, prepare 187ms)


 PASS  Waiting for file changes...
       press h to show help, press q to quit

もしmockがないとテストを実行した場合はgoogle is not definedが返ってきます。
@soleo/google-maps-vitest-mocksでモックを作成してテストを実行しましょう。

In-Source Testing

VitestではIn-source Testingを実行することができます。In-source Testingとは、実装コードと同じソースファイルにテストコードを記載し、そちらを実行できるというものです。Rustで有名なアプローチのようです。Rustで有名なアプローチのようです。
公式ドキュメントに記載されているように、tsconfig.json, vite.config.tsに1、2行追加するだけで実施できます。

https://vitest.dev/guide/in-source.html

メリット

「Vitest テストコードを実装ファイルと同一のファイルに記述する」の記載を引用します

・ private にしたい目的で export したくない関数をテストできる
・ 実装とテストの距離が近いのでテストが書きやすい(私はテストコードを書くときだけいつもエディタの画面を分割して表示してます)
・ さっとプロトタイプのコードを書くたいときに素早く書ける

https://zenn.dev/azukiazusa/articles/vitest-same-test-file

お試し

実際にクラスやメソッドを定義しているファイルの中にテストコードを書いていきます。

// CustomPolyline.ts

// 実際にモデルやメソッドを定義する部分
export class CustomPolyline {
    // 省略

    isEditable(hasAdminRole: boolean): boolean {
        if (hasAdminRole) {
            return true;
        } else {
            return this.isOwnPolyline;
        }
    }
}

// モデルやメソッドのテストを書く部分
if (import.meta.vitest) {
    const { it, describe, expect } = import.meta.vitest;

    describe('CustomPolylineを編集可能かどうかを判定するメソッドであるisEditableのテスト', () => {
        // 省略
    });
}

これでテストをすることが可能です。
if(import.meta.vitest)を記載しているのはプロダクションビルド時にテストコードがバンドルファイルに含まれないようにするためです。

注意点

In-Source Testingを用いてテストを実行する際は、tsconfig.jsonが存在する階層で実行してください。
tsconfig.jsonの設定が読み込めずに、失敗してしまいます。

最後に

今回は@soleo/google-maps-vitest-mocksを使って、Vitestを使った場合でもGoogle Map APIを使ったテストコードを書いてみました。
Jestと書き方が若干異なる部分もありますが、大きな違いではないので、スムーズに書けると思います。
Jestよりも早く実行できます。Viteを使った環境下ならばぜひ使っていきたいですね。

Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion