vitest in-source testing はいいぞ

に公開

はじめに

こんにちは!
最近は就活から逃げてニッチな技術系イベントに参加し、企業の方に「学生なのにこんなイベントに来ていて偉いね」と褒められることが生きがいの 27 卒学生エンジニアの yossuli です。
本記事は #Progate_Bar での発表内容を記事にしたものです。
今回は僕が個人開発で テストを書こうと思った際に、別の LT で vitest の in-source testing を知って取り入れてみたところ、例えば util 関数のテストを行う際にとても開発体験が向上したので、その理由と具体例を紹介します。

in-source testing とは?

詳細は僕が in-source testing を知ったきっかけである LT の以下のスライドをご覧ください。
https://speakerdeck.com/taro28/vitestnoin-source-testinggabian-li?slide=17

ざっくり以下のような感じです

import { describe, it, expect } from "vitest";

const add = (a: number, b: number) => a + b;

if (import.meta.vitest) {
  describe("add", () => {
    it("should add two numbers", () => {
      expect(add(1, 2)).toBe(3);
    });
  });
}

このように、テストコードを実装コードと同じファイルに書くことができるのが in-source testing です。

何がいいの?

上記のスライドにメリットは様々紹介されているので、ここでは実際に僕が 2 か月ほど in-source testing を使ってみて感じたメリットを紹介します。

テストコードが実装と近い

すごく単純ですがこれに尽きます。
複数のファイルを開かなくて、少し視点を下に移動するだけでテストコードが見えるので、様々に活用できます。

テストをメモにする

テストを先に書いて、引数と返り値をあらかじめ明示しておくことで実装するときにイメージがつきやすくなります。
また、テストを先に書いて vitest --watch を実行しておくことで変更を検知して即座にテストを実行してくれるので、現在の実装がどのような出力をするのかを確認しながら実装を進めることができます。
後で見返すときにも in-source testing のテストコードをドキュメントチックに使うことができます。

AI にテストファイルとの対応関係を明示しなくていい

AI を使って実装を進める際に、テストファイルと実装ファイルの対応関係を明示しなくてもそのファイルにテストコードが書いてあるので、AI が勝手に読み取ってくれます。
GitHub Copilot を agent モードで使う際にはより顕著に良さを実感しますが(勝手にテストを実行して間違っていたら修正をしてくれる)そうでなくても、推論の精度が上がっている気がします
(確実に、関数名だけでは表現しきれないニュアンスを、出力結果があることでそれに沿うような実装をサジェストしてくれている気がします)

プロダクトの構造が分かりやすい

別ファイルでテストを書く際には __tests__ ディレクトリにテストコードを置くことが多いと思います。
この際にターミナルや vscode の ctlr(cmd) + o でファイルを開く際に現在いる階層に該当するテストがないため、__tests__ ディレクトリに移動してからファイルを開く必要があります。
これを改善するために同じディレクトリにテストを書くことも選択しに上がるかなと思います。こうすることで、ターミナルから簡単に開くことができるだけでなく、vscode の ctlr(cmd) + o でファイルを開く際にも現在いるファイルのすぐ下がテストファイルになるため、矢印キー一回で目的のファイルを開くことができます。

$ code hoge.ts
# press upArrowKey
# $ code hoge.ts

# press backspace
# $ code hoge.t

# type est.ts
# $ code hoge.test.ts

$ code hoge.test.ts

しかしながら、このようにテストファイルを配置するとディレクトリ内の見通しが悪くなってしまいます

$ ls
hoge.ts
hoge.test.ts
fuga.ts
fuga.test.ts
piyo.ts
piyo.test.ts

insource testing を使うとテストファイルを分ける必要がなくなるため、ディレクトリ内の見通しが良くなります。

$ ls
hoge.ts
fuga.ts
piyo.ts

改めて tree コマンド等でプロダクトの構造を見返す際にも余分なファイル、ディレクトリがなくなり、プロダクトの構造が分かりやすくなります。

😣😣😣

$ tree
.
├── src
│   ├── utils
│   │   ├── hoge.ts
│   │   ├── hoge.test.ts
│   │   ├── fuga.ts
│   │   ├── fuga.test.ts
│   │   ├── piyo.ts
│   │   └── piyo.test.ts
│   └── index.ts
└── package.json
$ tree
.
├── src
│   ├── utils
│   │   ├── __tests__
│   │   │   ├── hoge.test.ts
│   │   │   ├── fuga.test.ts
│   │   │   └── piyo.test.ts
│   │   ├── hoge.ts
│   │   ├── fuga.ts
│   │   └── piyo.ts
│   └── index.ts
└── package.json

😊😊😊

$ tree
.
├── src
│   ├── utils
│   │   ├── hoge.ts
│   │   ├── fuga.ts
│   │   └── piyo.ts
│   └── index.ts
└── package.json

特にデメリットがない

in-source testing を使っても対応するツールでビルドを行えばビルド後のファイルにはテストコードが含まれないため、特にデメリットはありません。

まとめ

in-source testing を使うことで、テストコードを実装コードと同じファイルに書くことができ、開発体験が向上します。
特に個人開発では、テストコードをメモのように使うことでわざわざ別にドキュメントを用意せずに自分で分かる程度に実装の意図を残すことができるので、個人開発でのテストコードの書き方としてはとてもおすすめです。

ちなみに、本記事以外にも 4 本、今回の LT に関連して記事を挙げていますのでそちらも併せてご覧いただけると幸いです。
xのフォローもよろしくお願いします!

Discussion