rspec-daemon と VSCode を組み合わせて最強のテスト環境を作る


2023年 06月 22日

こんにちは、@tk0miya です。

僕が RubyKaigi で見つけたもので、一番面白そうだと思ったものが初日の LT で発表された rspec-daemon です。

rspec-daemon は rspec のデーモン化することによって、起動時間のオーバーヘッドを減らして、高速にテストを繰り返し実行することを目的としています。

rspec-daemon を動かしてみよう

まずは普通に rspec-daemon を動かしてみましょう。
Gemfile に依存を書いて bundle install してください。

group :development, :test do
  gem 'rspec-daemon', require: false
end

そして、以下のコマンドで起動します。

bundle exec rspec-daemon

rspec-daemon が起動したあとは、テスト対象のファイル名を TCP 経由で投げ込みます。
README では以下の方法が紹介されていますね。

echo 'spec/models/user_spec.rb' | nc -v 0.0.0.0 3002

残念ながら、手元の環境 (ruby:3.1 の Docker イメージ) では、この方法ではうまく行かなかったため、以下のコマンドで実行をしました。

ruby -rsocket -e 'TCPSocket.new("localhost", 3002).tap { |s| s.write("spec/models/user_spec.rb"); s.close_write; puts s.read; s.close }'

※ close_write のところがポイントです。デバッグした限り、ソケットの読み込みが終わらずにブロックしてしまうようです。

このコマンドを呼ぶと、rspec-daemon 上でテストが実行され、その結果がテキストとして返ってきます。
初回の実行はソースコードのロードが走るためか、少し時間がかかりますが、2回目以降は非常に高速にテストが実行されます。
もちろん、spec そのものやテスト対象のコードを書き換えてからテストを実行しても、変更内容はテストに反映されます。

実際の導入を考える

README 通りではないものの、少し工夫することで意図通り動くことが確認できましたが、テストを動かすたびに先ほどのコマンドを実行するというのは少し面倒です。
コマンドそのものが複雑で覚えづらいというのもありますが、エディタとターミナルを行き来するのは非常に不便です。

さて、そういうときに最初に手を出すのは VSCode 拡張ですよね。
ということで、VSCode 拡張として rspec-daemon を作ってみました

この拡張は以下のコマンドパレットから以下の操作が可能です

  • rspec-daemon の起動、終了
  • 現在開いているファイルのテストを rspec-daemon で実行
    • spec ファイルを開いている場合は、該当の spec ファイルのテストを実行する
    • .rb ファイルを開いている場合は、対応する spec ファイルを推測して、そのテストを実行する
  • 現在開いているファイルのウォッチをして、変更時にテストを自動実行する

実際には以下の動画を見てもらうとわかりやすいと思います。

拡張を作り始めたときはコマンドパレットからテストが一発で起動できればいいや、と考えていたのですが、
ふと思いついてウォッチモードを作ってみたところ、これが思いのほか便利でした。

まとめと感想

  • rspec-daemon gem の紹介
  • VSCode 拡張 rspec-daemon の紹介

今回、VSCode 拡張をいちから書き起こすのをはじめてチャレンジしました (パッチは投げたことがありましたが、最初からははじめて)。
プロジェクトのジェネレータが用意されていて、API リファレンスも充実しているので、比較的簡単に VSCode 拡張を作ることができました。
VSCode の機能が膨大で、欲しい機能を見つけるのに苦労した部分はありますが、全体的には良い開発体験だったと思います。
リビングでジロ・デ・イタリアとプレミアリーグを観戦しつつ、3-4時間でこのくらいの拡張が作れるというのには感動しました。

また、素晴らしいツールである rspec-daemon を開発された asonas さんには感謝したいと思います。
とても面白そうなツールで、勢いまかせで VSCode 拡張を作るモチベーションになりました。

みなさん、便利に使ってみてください。