3月26日、Astroチームが「MochaからNode.jsへの500以上のテストの移行」と題した記事を公開した。この記事では、AstroのテストランナーをNode.jsに移行する過程での詳細な経験が紹介されている。
Astroチームは、開発環境の最適化を図るため、MochaからNode.jsへのテストランナーの移行を検討していた。その理由の一つとして、CIのジョブの高速化を挙げており、Mochaには十分な満足感があったものの、常に改善を模索していた。
具体的な利点として、AstroのメインモノレポであるAstro monorepoにおいて、MochaとChaiの2つの依存関係を削減できる点が挙げられる。また、Node.jsプロジェクトのメンテナンスにはより多くの人々が関与しており、将来的な利点も期待されている。
この移行において、Astro monorepoには664のスイート、合計1603のテストがあり、その多くが統合テストであることが明らかになった。統合テストは、Astroプロジェクトを構築し、特定の環境(開発、静的生成(SSG)、動的生成(SSR))でそのプロジェクトをビルドし、ビルドされたページにアサーションを実行するものである。
移行を行う前に、Mochaから離れることが適切かどうかを確認したいと考えていたAstroチームは、Proof of Concept(PoC)を行った。その結果、Node.js CLIの柔軟性やテストレポーターのカスタマイズ可能性、テストスイートの実行速度、開発者のエクスペリエンスなどについて理解を深めることができた。
Node.jsの assert
と chai
の違い
移行作業の中でも大きなウェイトを占めたのは、chai
ライブラリをnode:assert/strict
に置き換える作業である。例えば chai
は、等価性のチェックを少なくとも4つの異なる方法で実行できる。
import { expect } from "chai";
expect("foo").to.eq("foo")
expect("foo").to.be.eq("foo")
expect("foo").to.equal("foo")
expect("foo").to.be.equal("foo")
一方で、このような柔軟性を持つことは良い面もあるが、テストのコードが一貫性を欠くことになる。Node.jsのアサーションモジュールでは、このチェックを行うための方法が1つしかない。
import { assert } from "node:assert/strict";
assert.equal("foo", "foo")
Astroチームは chai
の機能を最小限しか利用していなかったため、Node.jsのアサーションモジュールへの移行は思ったよりも苦労しなかったという。ただし、以下の includes
のようなユーティリティは、Node.jsでは提供されていない。
import { expect } from "chai";
expect("It's a fine day").includes("fine")
代わりにString#includes
関数と assert.equal
を組み合わせて使用することで対処した。コードのわかりやすさや、テスト失敗時のメッセージの詳細度などについては、まだ chai
に分があると言ってよいだろう。
import assert from "node:assert/strict";
assert.equal("It's a fine day".includes("fine"), true)
直面した問題
移行作業中に、Astroチームはいくつかの課題に直面した。特に、 Node.jsテストランナーがMochaよりも遅い ことが判明したことに驚いた。この遅延は、Node.jsが各テストファイルごとに新しいプロセスを起動し、各テストスイートを独立して実行するために起こっていた。しかし、Astroのテストスイートはすでに分離されており、Mochaを使用しても問題がなかったため、このアプローチは効率的ではなかった。
この問題を解決するため、Astroチームはastro-scripts test
コマンドを使用して独自のスクリプトを作成した。このスクリプトを使用することで、すべてのテストスイートを同じスレッドで実行できるようになり、パフォーマンスの問題が解消された。ただし、この方法には欠点もあり、テストの失敗やタイムアウトが発生した場合、原因の特定が難しくなる可能性がある。
移行の結果
Astroチームは移行作業の結果に満足しており、テストのパフォーマンスに大きな問題はないことを確認した。Node.js提供のアサーションモジュールには必要な機能がほとんど含まれており、describe
/it
パターンもサポートされているため、Mochaからの移行はスムーズに行われた。
ただし、Mochaと比較して、開発者のエクスペリエンスに関するいくつかの問題が残っている。たとえば、Mochaではit.only
を使用するだけで単一のテストスイートを実行できるが、Node.jsテストランナーでは追加の手順が必要である点などが挙げられる。
詳細はMigrating 500+ tests from Mocha to Node.jsを参照していただきたい。
彼らの努力と綿密な計画により、テストのパフォーマンスは向上し、将来の開発に向けた堅固な基盤が確立された。
1v1 lol