ESM アジャイル事業部 開発者ブログ

永和システムマネジメント アジャイル事業部の開発者ブログです。

Railsのsystem testにおいて実行行ごとにhookを追加するgemを作った

この記事は ESM アドベントカレンダー 2023 の9日目です。

こんにちは @color_boxです。

今回は system_test_step_hook というgemを作ったので、それについて書きます。

rubygems.org

こちらのgemはRailsアプリのsystem testで動作します。 テストコードの各行に対して、RSpecのbefore/after hookのように、何らかの処理の追加を可能にします。

使い方は簡単で、このgemをインストールして

SystemTestStepHook.before do
  pp 'this is before hook'
end

SystemTestStepHook.after do
  pp 'this is after hook'
end

のように追記すると、systemテストの各行に対して、before/after hookのようなタイミングで追記したコードが実行されます。

本記事では、こちらのgemを仕組みについて軽く解説できればと思います。

仕組み

そもそもsystem testにおいて、コード一行ずつの実行を検知するような仕組みはありません。

ですので、動的にテストコードを書き換えて実現します。

  1. system test実行時にテストコードが書かれたブロックを取り出す
  2. 取り出したコードブロックをParserで分解し、各行の前後で渡されたブロックを実行するコードを挿入
  3. 編集したコードをevalで実行し、結果を得る

という流れになります。

取り出したコードブロックを実際に編集している箇所が下記で https://github.com/colorbox/system_test_step_hook/blob/main/lib/system_test_step_hook.rb#L17-L35

編集したコードブロックをevalで実行して結果を得ているのが下記です。 https://github.com/colorbox/system_test_step_hook/blob/main/lib/system_test_step_hook.rb#L37-L68

Minitest::Testモジュールにモンキーパッチを当てて対応しています。

SystemTestStepHookのモジュール内で編集したコードをevalしてしまうと、編集前のコードと実行コンテキストが変わってしまうため、eval自体をMinitestのコンテキストで呼び出すようにしています。

目的

なぜこのようなgemを作ったかについてですが、それは下記のgemに組み込むための部品とするためです。

github.com

こちらのgemは、system testを実行するとスクリーンショットとテストコードを組み合わせてHTMLを作成し、それを仕様書として使えるようにするというgemです。 元々system testの行ごとに何らかの処理を行うという挙動はこちらのgemのものだったのですが、そのhookの部分のみを抽出した形になります。 単機能で切り出せばその分応用も効きますし、保守性が上がるというわけですね。


株式会社 永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。

agile.esm.co.jp