【Google Maps API】VitestでGoogle Maps APIを用いた処理のテストコードを書こう
この記事について
以前、「【Google Maps API】 @googlemaps/jest-mocksを使ってテストコードを書こう」という記事を書きました。これはJestを使って、Google Maps APIのテストを書こうというものです
今回はVitestバージョンです。Vitestを使って、Google Maps APIを書いていきます
先に結論を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と同じような記法で記載が可能です。
@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行追加するだけで実施できます。
メリット
「Vitest テストコードを実装ファイルと同一のファイルに記述する」の記載を引用します
・ private にしたい目的で export したくない関数をテストできる
・ 実装とテストの距離が近いのでテストが書きやすい(私はテストコードを書くときだけいつもエディタの画面を分割して表示してます)
・ さっとプロトタイプのコードを書くたいときに素早く書ける
お試し
実際にクラスやメソッドを定義しているファイルの中にテストコードを書いていきます。
// 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を使った環境下ならばぜひ使っていきたいですね。
Discussion