LoginSignup
5
2

RubyKaigi 2024で発表されたRSpecテストコード生成ツール Omochi についてまとめてみた

Last updated at Posted at 2024-06-05

はじめに

私は株式会社エル・ティー・エス リンクでRailsエンジニアをしているysk_ymdyと申します。
担当サービスは、IT人材と案件のマッチングプラットフォーム アサインナビです。

先日「RubyKaigi 2024」に参加し、たくさんの学びや気づきを得ることができました。
その中でも@mikiko_bridgeさんさんが発表された Omochi というgemが、私含めRailsで開発するエンジニアにとって大変役立つものなのではと思い、共有させていただきます。

Omochiってどんなgem?

ひとことで言うと、RSpecを導入しているRailsアプリケーションに対して、LLMを使ってテストコードを自動生成してくれるgemです。

Railsで開発する際、テストコードの作成は手間がかかったり抜け漏れが気になったりすることがあると思います。
その手助けになるツールがOmochiなんです💡

詳しい説明は、@mikiko_bridgeさんのGithubでの文面をお借りしながら以下で紹介いたします🙇‍♂️

Omochi is a CLI tool to support Ruby on Rails development with RSpec. It detects methods uncovered by tests and prints the test code generated by LLM.

Omochiは、RSpecを使用したRuby on Rails開発をサポートするCLIツールです。テストで発見されたメソッドを検出し、LLMによって生成されたテストコードを出力します。

There are two advantages of using Omochi. We can make sure every method is covered by tests with GitHub Actions support. We can also generate spec files for uncovered methods so that we can reduce time to write them manually.

Omochiを使用する利点は2つあります。GitHub Actionsのサポートにより、すべてのメソッドがテストでカバーされていることを確認できます。また、カバーされていないメソッドの仕様ファイルを生成することもできるため、手動で記述する時間を短縮できます。

どうやってOmochiを導入するの?

Githubでの記載(2024/5/31時点)を元に順を追って見ていきます。

まずは実行環境です。

  • ruby3.x
  • AWS Credentials (for --create)

が必要です。
AWS Credentialsについてはこちら

次にgemのインストールです。

$ gem specific_install -l https://github.com/mikik0/omochi.git

ここまでで一旦Omochiの導入は完了です。

Omochiを実行するには?

同じくGithubでの記載(2024/5/31時点)を元にシチュエーション別に見ていきます。

local_pathに対してspec(テスト)が正しく作成されているか確認したい時
(verifyコマンド)

$ omochi verify local_path

local_pathに対して新しくspecファイルを作成したい時
(--createオプション)

$ omochi verify local_path -c
# もしくは↓
$ omochi verify local_path --create

指定されたGithubプルリクエストに対してspecが正しく作成されているか確認したい時
(--githubオプション)

$ omochi verify local_path -h
# もしくは↓
$ omochi verify local_path --github

コマンドがわからなくなった時
(helpコマンド)

$ omochi --help
Commands:
  omochi help [COMMAND]     # 利用可能なコマンド全体、もしくは特定のコマンドの詳細を表示する
  omochi verify local_path  # 新しく作成されたすべてのメソッドおよび関数のために作成されたspec(テスト)を検証する。

基本的には、verify, helpコマンドのみのようですね👀

実行するとどうなるの?

こちらも同じくGithubでの記載(2024/5/31時点)のサンプルを元に見ていきます。

verifyコマンド-cオプションを実行してみると

$ omochi verify -c
"Verify File List: [\"lib/omochi/cli.rb\", \"lib/omochi/util.rb\"]"
"specファイルあり"
===================================================================
verifyのテストを以下に表示します。
require 'rspec'

describe 'exit_on_failure?' do
  it 'returns true' do
    expect(exit_on_failure?).to eq(true)
  end
end
======= RESULT: lib/omochi/cli.rb =======
- exit_on_failure?
"specファイルなし"
======= RESULT: lib/omochi/util.rb =======
- local_diff_path
- github_diff_path
- remote_diff_path
- get_ast
- dfs
- find_spec_file
- get_pure_function_name
- dfs_describe
- print_result
- get_ignore_methods
- create_spec_by_bedrock
===================================================================
lib/omochi/util.rbのテストを以下に表示します。
require "spec_helper"

describe "local_diff_path" do
  it "returns array of diff paths from git" do
    allow(Open3).to receive(:capture3).with("git diff --name-only", any_args).and_return(["path1", "path2"], "", double(success?: true))
    expect(local_diff_path).to eq(["path1", "path2"])
  end

  it "returns empty array if git command fails" do
    allow(Open3).to receive(:capture3).with("git diff --name-only", any_args).and_return("", "error", double(success?: false))
    expect(local_diff_path).to eq([])
  end
end

describe "github_diff_path" do
  it "returns array of diff paths from gh" do
    allow(Open3).to receive(:capture3).with("gh pr diff --name-only", any_args).and_return(["path1", "path2"], "", double(success?: true))
    expect(github_diff_path).to eq(["path1", "path2"])
  end

  it "returns empty array if gh command fails" do
    allow(Open3).to receive(:capture3).with("gh pr diff --name-only", any_args).and_return("", "error", double(success?: false))
    expect(github_diff_path).to eq([])
  end
end

describe "remote_diff_path" do
  it "returns array of diff paths from remote" do
    allow(Open3).to receive(:capture3).with(/git diff --name-only .*${{ github\.sha }}/, any_args).and_return(["path1", "path2"], "", double(success?: true))
    expect(remote_diff_path).to eq(["path1", "path2"])
  end

  it "returns empty array if git command fails" do
    allow(Open3).to receive(:capture3).with(/git diff --name-only .*${{ github\.sha }}/, any_args).and_return("", "error", double(success?: false))
    expect(remote_diff_path).to eq([])
  end
end

describe "get_ast" do
  it "returns AST for given file" do
    allow(File).to receive(:read).with("file.rb").and_return("code")
    allow(Parser::CurrentRuby).to receive(:parse_with_comments).with("code").and_return(["ast"], ["comments"])
    expect(get_ast("file.rb")).to eq([{ast: "ast", filename: "file.rb"}])
  end
end

describe "dfs" do
  let(:node) { double(:node, type: :def, children: [double(:child, children: ["name"])]) }
  let(:result) { {} }

  it "traverses node and captures def names" do
    dfs(node, "file.rb", result)
    expect(result).to eq({"name" => "def name\nend"})
  end
end

describe "find_spec_file" do
  before do
    allow(File).to receive(:exist?).with("spec/app/file_spec.rb").and_return(true)
  end

  it "returns spec file path if exists" do
    expect(find_spec_file("app/file.rb")).to eq("spec/app/file_spec.rb")
  end

  it "returns nil if spec file does not exist" do
    allow(File).to receive(:exist?).with("spec/app/file_spec.rb").and_return(false)
    expect(find_spec_file("app/file.rb")).to be_nil
  end
end

# similarly test other functions

このように、生成してくれたコードを.specファイルにコピペするとテストが出来上がるようです🙌
以上が、Omochiの実行結果です。

さいごに

Omochiで作成されるテストコードは、LLMが生成するコードのためまだ完璧とは言えないようですが、
Omochi実行

コピペ

部分を修正
とspecを書く手間がかなり省けそう かつ メソッドレベルでOmochiが確認してくれるため人間が0から書くより網羅性を担保できそうですね!

@mikiko_bridgeさんもこちらの記事にて、

Omochi は、開発初期段階であり、以下の機能強化を予定しています。
コード構造の改善による可読性向上
Request spec 対応
Omochi自体のSpecを増やす
GitLab 対応
Omochi は、今後も Ruby on Rails 開発を支援するCLI ツールとして、進化し続けていく予定です。

と今後の展望をお話ししてくださっています。
Railsエンジニアを助ける強力なツールOmochiから今後も目が離せないですね!👀
ローカル環境でデモ等した際、追記していきます。

参考

5
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2