0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vitestの特徴と基本的な使い方

0
Posted at

本記事の執筆にはAIを使用しています。

はじめに

Vitestの特徴、基本的な使い方、主要な関数を紹介します。
初めてVitestを使う方が、テストを書いて実行できるところまでを扱います。

「Vitest」とは?

Viteを利用したJavaScript・TypeScript向けのテストフレームワークです。

「Vitest」は「ヴィーテスト」と読みます。
Viteを使っていないプロジェクトでも利用できます。

環境

  • Node.js: 24.13.0
  • npm: 11.10.0
  • Vitest: 4.1.10

Vitest 4.1.10は、Node.js 22.12.0以上とVite 6.4.0以上を必要とします。

特徴

Viteの設定を共有できる

Vitestは、デフォルトで vite.config.* を読み込みます。
Viteのプラグインやエイリアスなどを、テストでもそのまま使えます。
開発・ビルド・テストで設定が分かれにくいのがメリットです。

TypeScriptとJSXをそのまま扱える

TypeScriptやJSXを追加設定なしで変換できます。
ES Modulesにも対応しています。

変更に関係するテストだけを再実行できる

開発環境で vitest を実行すると、デフォルトでウォッチモードになります。
ソースコードやテストを変更すると、Viteのモジュールグラフを使って関係するテストだけを再実行します。
CIでは、環境変数 CI が存在すると自動で1回だけ実行します。

Jestに近いAPIを使える

テストの書き方、アサーション、モック、スナップショットはJestと互換性のあるAPIです。
Jestを使ったことがあれば、似た書き方で始められます。

テストに必要な機能が揃っている

主に次の機能があります。

  • V8またはIstanbulによるカバレッジ計測
  • vi によるモック、スタブ、スパイ
  • スナップショットテスト
  • jsdom または happy-dom を使ったDOMのモック
  • 実ブラウザでテストするBrowser Mode
  • テストファイルの並列実行
  • 型テスト
  • ベンチマーク

基本的な使い方

インストールする

プロジェクトへVitestをインストールします。

$ npm install --save-dev vitest

テスト対象を作る

例として、2つの数値を足す関数を作ります。

src/sum.ts
export function sum(a: number, b: number): number {
  return a + b
}

テストを書く

ファイル名に .test. または .spec. を含めると、デフォルトでテストファイルとして認識されます。

src/sum.test.ts
import { describe, expect, test } from 'vitest'
import { sum } from './sum'

describe('sum()', () => {
  test('2つの数値を足す', () => {
    expect(sum(1, 2)).toBe(3)
  })
})

describe() で関連するテストをまとめます。
test() でテストケースを定義し、 expect() で結果を検証します。

npmスクリプトを追加する

package.json へテスト用のスクリプトを追加します。

package.json
{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run"
  }
}

テストを実行する

開発中はウォッチモードで実行します。

$ npm test

1回だけ実行する場合は、 vitest run を使います。
CIではこちらを使うと、実行後にプロセスが終了することが明確です。

$ npm run test:run

ファイル名を指定すると、実行するテストを絞れます。

$ npm run test:run -- src/sum.test.ts

主要な関数一覧

テストを定義する関数

関数 説明
test(name, fn) テストケースを定義する。 it() は別名
describe(name, fn) 関連するテストをまとめる。 suite() は別名
expect(value) 値を受け取り、マッチャーで検証する
assert.* Chaiのアサーションで検証する
expectTypeOf(value) TypeScriptの型を検証する
assertType(value) 値が指定したTypeScriptの型に一致するか検証する
bench(name, fn) 実験的なAPIでベンチマークを定義する

test()describe() には、実行方法を変える修飾子があります。

修飾子 説明
.only 指定したテストやスイートだけを実行する
.skip 指定したテストやスイートを実行しない
.todo 未実装のテストとして記録する
.concurrent 複数のテストを並行して実行する
.fails 失敗することを想定したテストとして記録する
.each 表形式のデータを使って、同じテストを繰り返す

例えば test.each() を使うと、複数の入力を短く書けます。

test.each([
  [1, 2, 3],
  [2, 3, 5],
])('sum(%i, %i)は%iを返す', (a, b, expected) => {
  expect(sum(a, b)).toBe(expected)
})

セットアップと後片付けをする関数

関数 実行するタイミング
beforeAll(fn) スイート内の全テストを実行する前に1回
afterAll(fn) スイート内の全テストを実行したあとに1回
beforeEach(fn) スイート内の各テストを実行する前
afterEach(fn) スイート内の各テストを実行したあと
onTestFinished(fn) 現在のテストが終了したあと
onTestFailed(fn) 現在のテストが失敗したあと

describe() の中で呼ぶと、そのスイート内のテストにだけ適用されます。
非同期の処理では、Promiseを返すか async 関数を渡します。

import { afterEach, beforeEach, describe, expect, test } from 'vitest'

describe('users', () => {
  beforeEach(async () => {
    await seedUsers()
  })

  afterEach(async () => {
    await clearUsers()
  })

  test('ユーザーを取得する', async () => {
    await expect(fetchUsers()).resolves.toHaveLength(1)
  })
})

よく使うマッチャー

マッチャー 説明
toBe(expected) プリミティブ値や同じオブジェクトかを比較する
toEqual(expected) オブジェクトの中身を再帰的に比較する
toStrictEqual(expected) オブジェクトの型や未定義のプロパティも含めて厳密に比較する
toBeTruthy() / toBeFalsy() 真または偽として扱われる値かを検証する
toBeNull() / toBeUndefined() null または undefined かを検証する
toContain(value) 配列や文字列に値が含まれるかを検証する
toMatch(pattern) 文字列が文字列または正規表現に一致するかを検証する
toHaveLength(length) 文字列や配列の長さを検証する
toHaveProperty(key, value?) オブジェクトがプロパティを持つかを検証する
toThrow(error?) 関数が例外を投げるかを検証する
toMatchSnapshot() 値が保存済みのスナップショットと一致するかを検証する
toHaveBeenCalled() モック関数が呼ばれたかを検証する
toHaveBeenCalledWith(...args) モック関数が指定した引数で呼ばれたかを検証する

否定するときは .not を付けます。
Promiseの成功を検証するときは .resolves 、失敗を検証するときは .rejects を付けて await します。

expect(sum(1, 2)).not.toBe(4)
await expect(Promise.resolve('OK')).resolves.toBe('OK')
await expect(Promise.reject(new Error('失敗'))).rejects.toThrow('失敗')

モックを扱う主な関数

モック関連の関数は、 vi オブジェクトにまとまっています。

関数 説明
vi.fn(implementation?) モック関数を作る
vi.spyOn(object, method) 既存オブジェクトのメソッドを監視する
vi.mock(path, factory?) モジュールをモックする
vi.mocked(value) TypeScript上でモックの型を付ける
vi.clearAllMocks() すべてのモックの呼び出し履歴を消す
vi.resetAllMocks() 履歴を消し、モックの実装をリセットする
vi.restoreAllMocks() vi.spyOn() で置き換えたメソッドを元へ戻す
vi.useFakeTimers() 日時やタイマーをテスト用の偽物へ置き換える
vi.useRealTimers() 本物の日時やタイマーへ戻す
vi.stubGlobal(name, value) グローバル変数を一時的に置き換える
vi.stubEnv(name, value) 環境変数を一時的に置き換える
import { expect, test, vi } from 'vitest'

test('コールバックを1回呼ぶ', () => {
  const callback = vi.fn()

  callback('hello')

  expect(callback).toHaveBeenCalledOnce()
  expect(callback).toHaveBeenCalledWith('hello')
})

おわりに

Vitestは、短い設定でTypeScriptのテストを始められます。
まずは test()describe()expect() から使い、必要に応じてフックやモックを追加してみてください :relaxed:

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?