昨年登壇した福岡Rubyist会議04では、「Ruby本体のparse.yをサードパーティライブラリとして使えるようにする」という試みについて発表しました。
またその時に作ったライブラリのKanayago(金屋子)はこちらです。
当時はまだ一部のASTノードしか対応しておらず、実際にライブラリとして利用するのは難しい状況でした。登壇後も細々と実装を続け、つい先日ようやく全てのASTノードに対応しました。
「これでRubyのコードがパースしていじれる」ようになったので「せっかくだし何かKanayagoを使ったツールを作りたいな」と思い、Igata(鋳型)というツールを作ってみました。
Rubyのコードを渡すことでMinitestまたはRSpecのテストコードの雛型を作ってくれるツールになります。
テストの雛型作成ツールを作ろうと思ったきっかけとしては、後述する omochi の存在と、「実務でも使えるツールの方がドッグフーディングとして良さそうだ」と考えたからです。
利用シーンとしては
- テストコードがないライブラリへの追加するテストコードを生成
- Railsなどで仮置きで実装したモデルのコードへテストを生成する
などを考えています
主な利用シーンとしては、既存のコードベースにテストを追加する場面を想定しています。
また実装の着想としてはRubyKaigi 2024のLTで紹介されていた omochi から得ました。 僕自身もLTで登壇しており、ちょうど前の枠が omochi の発表だったこともあり印象に残っています。
「テストコードを生成する」という点では omochi と同じ方向性のツールですが、Igataでは「複数のテストフレームワークに対応したい」「テストを書く際に面倒な構造を自動生成したい」「RubyのASTノードを直接扱いたい」といった意図を持って実装しています。
使い方
基本的にはCLIツールとして利用します。
# デフォルトではMinitestの雛型が生成される bundle exec igata lib/user.rb > test/test_user.rb # -f rspecでRSpecの雛型が生成される bundle exec igata lib/user.rb -f rspec > spec/user_spec.rb
例えば以下のようなコードを渡すと
class User def initialize(name, age) @name = name @age = age end def adult? @age >= 18 end end
以下のようなMinitestの雛型を生成したり
# frozen_string_literal: true require "test_helper" class UserTest < Minitest::Test def test_initialize skip "Not implemented yet" end def test_adult? # Comparisons: >= (@age >= 18) skip "Not implemented yet" end end
このようなRSpecの雛型を生成することができます。
# frozen_string_literal: true require "spec_helper" RSpec.describe User do describe "#initialize" do it "works correctly" do pending "Not implemented yet" end end describe "#adult?" do # Comparisons: >= (@age >= 18) it "works correctly" do pending "Not implemented yet" end end end
Kanayago経由でメソッド内の条件分岐などの情報が取得できるので Comparisons: >= (@age >= 18)のようなコメントも追加で出力するようにしています。
こうしたコメントを自動で出力することで、テスト設計時に条件分岐の意図を素早く把握できますし、将来的にはLLMを活用してテストケースを自動生成する際の補助情報としても活かせるのではと思ってこうしています。
今後
一旦は個人的に作っているライブラリなどで試しつつ、Railsのrequest specやmodel specなども対応していきたいと思います。 またKanayago自体の改善やparse.yに投げているキーワードの位置情報を追加対応なども進められれば、より便利なテストの雛型を生成できるようになると考えています。