この記事は ESM アドベントカレンダー 2023 の9日目です。
こんにちは @color_boxです。
今回は system_test_step_hook というgemを作ったので、それについて書きます。
こちらの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において、コード一行ずつの実行を検知するような仕組みはありません。
ですので、動的にテストコードを書き換えて実現します。
- system test実行時にテストコードが書かれたブロックを取り出す
- 取り出したコードブロックをParserで分解し、各行の前後で渡されたブロックを実行するコードを挿入
- 編集したコードを
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に組み込むための部品とするためです。
こちらのgemは、system testを実行するとスクリーンショットとテストコードを組み合わせてHTMLを作成し、それを仕様書として使えるようにするというgemです。 元々system testの行ごとに何らかの処理を行うという挙動はこちらのgemのものだったのですが、そのhookの部分のみを抽出した形になります。 単機能で切り出せばその分応用も効きますし、保守性が上がるというわけですね。
株式会社 永和システムマネジメントでは、Ruby とアジャイルソフトウェア開発を通じてコミュニティと成長したいエンジニアを絶賛募集しています。