Masayan tech blog.

  1. ブログ記事一覧>
  2. 【Vitestで始める単体・結合テスト】関数テストの環境構築と作成

【Vitestで始める単体・結合テスト】関数テストの環境構築と作成

公開日

環境

  • macOS Monterey 12.6
  • VSCode
  • node.js v18.6.0
  • npm 8.13.2
  • Typescript ^5.0.2
  • vite ^4.4.5
  • vitest ^0.34.2

前置き

今テスト始めるならどんな構成がいい?

巷ではjestはオワコン化してきているらしい。単体・結合テストは実行速度がとても重要なわけだが、vitestはjestよりも高速である点が注目されている。

実際、State of javascript 2022でも、JestよりVitestが上位に来ている。(フロントエンドの流行り廃りの変化早すぎて鬱なるわ。。)

従来のjestよりも高速でstate of javascript2022(JavaScriptに興味を持つ世界中のIT技術者3万9472人が回答したアンケートの結果をまとめた)でもJestの利用率を抜いて1位に

本記事で説明すること

本記事では、実務でvitestを用いてテスト環境構築とテストの作成を行うことがあったので、その経験をもとに以下の内容を説明する。なお、関数テストの部分のみ本記事で、それ以降は本記事最後に紹介している別記事を参照されたし(vue、reactそれぞれ別記事で紹介する)

  • 関数テスト
    • 環境構築
    • 関数の実装
    • テスト作成
    • 実行
  • コンポーネントテスト(vue、reactそれぞれ)
    • 環境構築
    • コンポーネントの実装
    • テスト作成
    • 実行
  • カスタムHooksのテスト(Vueならcomposable関数)
    • 関数の実装
    • テスト作成
    • 実行

reactを使用したケースはこちら

【Vitestで始める単体・結合テスト】ReactコンポーネントとカスタムHooksのテストの環境構築と作成(testing-library/react)

vueを使用したケースはこちら

【Vitestで始める単体・結合テスト】VueコンポーネントとComposable関数のテストの環境構築と作成(testing-library/vue)

【Vitestで始める単体・結合テスト】Vueコンポーネントテストの環境構築と作成(vue-test-utils)

コンポーネントテスト全般のTIPSなどまとめはこちら

【Vitestで始める単体・結合テスト】保守性の高いテストのTIPSやポイント

関数テスト

コンポーネントのテストを実行するためには、まずピュアなJavaScript(TypeScript)の関数テストが実行できる環境を作る必要があるので、そこから説明する

環境構築

vitestの環境構築はまだまだネット上に情報が少ない。そのため以下のvitest公式リポジトリに用意されているような構成を参考にするといい。vueやreact、next.jsなどのそれぞれの技術スタックの組み合わせに応じたサンプル設定を見ることができるので必要に応じて参考されたし。

https://github.com/vitest-dev/vitest/tree/main/examples

Viteプロジェクトの作成(すでにプロジェクトがある場合はスキップしろください)

npm create vite@latest

フレームワーク選択

プロジェクト作る時に使用するUIフレームワークを聞かれるのでお好みのものを選択(今回は例としてvue)

依存関係インストールと開発サーバー起動

npm install && npm run dev

http://localhost:5174/ にアクセスすると、ブラウザで画面を確認できる

Vitest のインストール

アサートメソッド、マッチャーなどを提供するテスト基盤ピュアなJavaScriptやTypeScriptの関数、クラステスト用のviteベースのライブラリ

npm install -D vitest

テスト用ディレクトリの作成

プロジェクトルートに対してtestsディレクトリを作成する

mkdir tests

テストディレクトリ(ファイル)をtypscriptが認識できるようにする

※testファイルもsrc内に置く場合は以下の追加は不要

{
  "compilerOptions": {
    ・・・
  },
  "include": ["tests/**/*.ts"],
}

Viteの設定ファイル調整

Vitestの型への参照を追加

vite.config.tsの先頭にrefereceを追加

vitest公式より引用

vitest自体を設定するには、Viteのconfigにtestプロパティを追加します。また、vite自身からdefineConfigをインポートする場合は、設定ファイルの先頭にトリプルスラッシュでVitestの型への参照を追加する必要があります。

vite.config.ts

/// <reference types="vitest" />
import { defineConfig } from "vitest/config";
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()], // ここは選択したフレームワークやライブラリごとに自動で指定される
});

※refereceがないと、以下のdefineConfig.testの設定ができないため必要

defineConfig.testのglobalsをtrueにする。これにより、describe, expect, testなどのvitestのapiをテストファイル全体でglobalに扱うことができ、テストファイルごとにimportする必要がなくなる

https://vitest.dev/config/#globals

/// <reference types="vitest" />
import { defineConfig } from "vitest/config";
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()], // ここは選択したフレームワークやライブラリごとに自動で指定される
  test: {
    globals: true, //here
  },
});

以下も忘れずに、

tsconfig.json

{
  "compilerOptions": {
    ・・・割愛
    "types": ["vitest/globals"]
  },

上記により、各テストファイルでvitestからのimportが不要になる

// something.test.ts
import { describe, it, expect } from "vitest"; ←これが不要になる
import { render } from "@testing-library/vue";

テストコマンドを追加

package.json

{
  "name": "vue-vitest",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    "test": "vitest" // here
  },

関数の実装

Dateオブジェクトをフォーマットして返すシンプルな関数

src/functions/Date/formatDate.ts

export const formatDate = (date: Date) => {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
};

テスト作成

tests/functions/Date/formatDate.test.ts

import { formatDate } from "../../../src/functions/Date/formatDate";

describe("formatDate", () => {
  test("日付オブジェクトを yyyy-mm-dd フォーマットできる", () => {
    const date = new Date("2023-07-28");
    const formattedDate = formatDate(date);
    expect(formattedDate).toBe("2023-07-28");
  });

  test("一桁の月と日は0詰め", () => {
    const date = new Date("2023-01-02");
    const formattedDate = formatDate(date);
    expect(formattedDate).toBe("2023-01-02");
  });

  test("うるう年", () => {
    const date = new Date("2024-02-29");
    const formattedDate = formatDate(date);
    expect(formattedDate).toBe("2024-02-29");
  });
});

実行

npm run test

パスエイリアスを設定できるように

srcディレクトリ以下を@のエイリアスでimportできるようにする

// ↓これがいや
import { formatDate } from "../../../src/functions/Date/formatDate";

tsconfig.json

pathsに追加

{
  "compilerOptions": {
    // here
    "paths": {
      "@/*": ["./src/*"]
    },
    ・・・
  }
}

vite.config.ts

aliasに追加

/// <reference types="vitest/config" />
import { defineConfig } from "vite";
import path from "path";

export default defineConfig({
  test: {
    // here
    alias: {
      "@": path.join(__dirname, "/src"),
    },
  },
});

@でimportできるようになった

tests/functions/Date/formatDate.test.ts

// here
import { formatDate } from "@/functions/Date/formatDate";

describe("formatDate", () => {
  ・・・
});

コードカバレッジを測定できるように

c8を依存関係に追加

npm install -D @vitest/coverage-v8

vite.config.tsに設定追加

test.coverage部分等を追記。textが標準出力、lcovが output ファイルを出力

/// <reference types="vitest" />

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [vue()],
  test: {
    coverage: {
      provider: "v8",
      all: false, // 未テストのコードもカバレッジに含める
      reporter: ["text"], // HTML,Clover,テキスト形式のカバレッジレポート
    },
  },
});

実行

npx vitest run --coverage

カバレッジがコンソール表示されるとともに、/coverageディレクトリに結果が出力される

本記事ではここまでで、別記事でvue、reactそれぞれのコンポーネントテストがテストできる環境の構築及びテストの作成を行う

まとめ

いかがでしたでしょうk。本記事では、viteベースのvitestで単体・結合テストの環境構築、関数テストの作成、カバレッジ測定の仕組み、パスエイリアスの設定などについて説明しました。今後、jestから置き換えられていくと思いますが、ネット上にはまだそれほど充実した記事はないので、ぜひ参考にして構築してみてください。