ソースコードを汚さずにRSpecをデバッグする技術 (rdbg)
はじめに
RSpec の挙動を確認したり、なぜ落ちるのかを調査したりするとき、みなさんはどうしていますか?
多くの方が、こんなフローになっていると思います。
- 怪しい箇所のソースコードを開く
-
binding.pry(あるいはbinding.break) を埋め込む - テストを実行して止める
- 調査が終わったら
binding.pryを消す
このフローにおける最大のストレスは、「デバッグのためにソースコードを書き換える必要がある」という点です。
Git の差分にデバッグコードが出てしまったり、うっかり消し忘れてコミットしそうになったり……。地味ながらも精神力を削られる作業です。
本記事では、Ruby 3.1 から標準添付されているデバッガ debug gem (rdbg) を使い、「コードを1文字も書き換えずに、任意の行・メソッドでブレークさせながら RSpec を実行する方法」を紹介します。
結論: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 行目で止めたい
-
まず RSpec を rdbg 経由で起動:
bundle exec rdbg -c -- bundle exec rspec spec/models/user_spec.rb -
(rdbg)プロンプトが出たら、そこからブレークポイントを貼る:(rdbg) break app/models/user.rb:30 -
あとは
continue(あるいは短縮のc):(rdbg) c -
テスト実行中に
user.rbの 30 行目に到達したタイミングで、そこにデバッガが止まります。
user.rb 側には binding.break も binding.pry も書いていません。
「ブレークポイントの設定だけを外側(rdbg コンソール)でやっている」イメージです。
この方法の何が嬉しいのか
1. Git の差分が汚れない
ソースを一切いじらないので、「デバッグコードの消し忘れ」リスクがゼロになります。
binding.pry を貼ったり剥がしたりするためにファイルを行き来する必要もありません。
2. 試行錯誤が高速化する
「あ、今の行じゃなくて、呼び出し元で止めたかったな」と思った時も、
-
breakを追加で打つ - いらなくなったら
deleteやdisableで消す
だけで済みます。
「コード書き換え → 保存 → テスト再実行」というループが消えて、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
補足:基本的なデバッグ操作
rdbg は pry-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.pryやbinding.breakをコードに埋め込むのは必須ではない。 -
bundle exec rdbg -c -- bundle exec rspec ...で RSpec を rdbg 経由で起動し、ブレークポイントは rdbg のコンソールからbreakコマンドで注入する。 - シェル関数で「rdbg 付き RSpec 起動」をラップしておくと、開発体験がかなり快適になる。
今まで binding.pry を手打ちしていた時間を節約して、
少しでも快適な Debug Life を送りましょう。
Discussion