🪓

ソースコードを汚さずにRSpecをデバッグする技術 (rdbg)

に公開

はじめに

RSpec の挙動を確認したり、なぜ落ちるのかを調査したりするとき、みなさんはどうしていますか?
多くの方が、こんなフローになっていると思います。

  1. 怪しい箇所のソースコードを開く
  2. binding.pry (あるいは binding.break) を埋め込む
  3. テストを実行して止める
  4. 調査が終わったら binding.pry を消す

このフローにおける最大のストレスは、「デバッグのためにソースコードを書き換える必要がある」という点です。
Git の差分にデバッグコードが出てしまったり、うっかり消し忘れてコミットしそうになったり……。地味ながらも精神力を削られる作業です。

本記事では、Ruby 3.1 から標準添付されているデバッガ debug gem (rdbg) を使い、「コードを1文字も書き換えずに、任意の行・メソッドでブレークさせながら RSpec を実行する方法」を紹介します。

https://github.com/ruby/debug

結論:RSpec を rdbg で包んでから break する

やりたいことはシンプルで、「RSpec を rdbg で起動して、デバッガのコンソールから break を打つ」だけです。Gemfile の設定変更も不要です(Ruby 3.1 以上、あるいは debug gem が入っていればOK)。

基本形

bundle exec rdbg -c -- bundle exec rspec spec/models/user_spec.rb

これで、

  • rdbg -c が「Ruby で書かれたコマンド(ここでは RSpec)」をデバッガ付きで起動し、
  • RSpec の実行開始位置で一旦停止した状態で (rdbg) プロンプトが出てきます。

例:app/models/user.rb の 30 行目で止めたい

  1. まず RSpec を rdbg 経由で起動:

    bundle exec rdbg -c -- bundle exec rspec spec/models/user_spec.rb
    
  2. (rdbg) プロンプトが出たら、そこからブレークポイントを貼る:

    (rdbg) break app/models/user.rb:30
    
  3. あとは continue(あるいは短縮の c):

    (rdbg) c
    
  4. テスト実行中に user.rb の 30 行目に到達したタイミングで、そこにデバッガが止まります。

user.rb 側には binding.breakbinding.pry も書いていません。
「ブレークポイントの設定だけを外側(rdbg コンソール)でやっている」イメージです。

この方法の何が嬉しいのか

1. Git の差分が汚れない

ソースを一切いじらないので、「デバッグコードの消し忘れ」リスクがゼロになります。
binding.pry を貼ったり剥がしたりするためにファイルを行き来する必要もありません。

2. 試行錯誤が高速化する

「あ、今の行じゃなくて、呼び出し元で止めたかったな」と思った時も、

  • break を追加で打つ
  • いらなくなったら deletedisable で消す

だけで済みます。
「コード書き換え → 保存 → テスト再実行」というループが消えて、rdbg のコンソール操作だけで完結します。

3. メソッド名でも止められる

行番号を調べるのが面倒な場合は、クラス名+メソッド名でブレークポイントを貼れます。

(rdbg) break User#save
#0  BP - Method  User#save (call)

これで、User#save が呼ばれたタイミングでデバッガが止まるようになります。

RSpec を起動するところまでは同じです:

bundle exec rdbg -c -- bundle exec rspec spec/models/user_spec.rb
# (rdbg) break User#save
# (rdbg) c

応用:もっと便利に使うための Tips

補足:基本的なデバッグ操作

rdbgpry-byebug と若干操作感が違いますが、
以下のコマンドさえ覚えておけばひとまず困りません。([GitHub][1])

コマンド 短縮形 説明
next n 1行進む(メソッドの中には入らない)
step s 1行進む(メソッド呼び出しがあれば中に入る)
continue c 次のブレークポイントまで進む
finish fin 現在のメソッドが終わるまで進む
outline ls 現在のコンテキストで使えるメソッド等を表示
backtrace bt バックトレース(呼び出し履歴)を表示
Enterキー - 直前のコマンドを繰り返すn 連打に便利)

ブレークポイントまわりでよく使うのはこの辺りです

コマンド 説明
break file.rb:line ファイル+行番号でブレークポイントを張る
break Class#method メソッド呼び出しで止める
break 現在登録されているブレークポイント一覧を表示
delete <id> 指定したブレークポイントを削除
disable <id> 一時的に無効化
enable <id> 再度有効化
VS Code などを使っている場合

本記事では CUI での操作に絞って解説しましたが、VS Code などのエディタを使っている場合は、それぞれの公式 Extension(VS Code なら VS Code rdbg Ruby Debugger)を導入することで、エディタ上でブレークポイントをポチポチ打つこともできます。
GUI 派の方はそちらもぜひ。

まとめ

  • binding.prybinding.break をコードに埋め込むのは必須ではない。
  • bundle exec rdbg -c -- bundle exec rspec ... で RSpec を rdbg 経由で起動し、ブレークポイントは rdbg のコンソールから break コマンドで注入する。
  • シェル関数で「rdbg 付き RSpec 起動」をラップしておくと、開発体験がかなり快適になる。

今まで binding.pry を手打ちしていた時間を節約して、
少しでも快適な Debug Life を送りましょう。

関連(して読んでほしい)URL

Discussion