背景
VSCodeの自動テストを取り扱う拡張機能に Test Explorer UIがある。
この拡張機能のruby用のadapterがRuby Test Explorerで、rspecとminitestを扱える。
また、Rubyを対象にBreakpointやstep実行が使えるようになるRubyという拡張機能もある。
こちらのバックエンドはruby-debug-ide
, debase
というgemで実現されている。
Ruby Test Explorerは、debug iconの駆動の際に、拡張機能としての"Ruby"を使う。
だいたいこんなイメージじゃないかという予想図
問題
Railsが自動生成するminitestに対してTest Explorer UIのビューからテストを走らせた時に、Breakpointが効かない。
もう少し細かく言うと、テストファイルの(main)コンテキストではbreakpointが効くが、テストブロックの中では効かない。
原因?
rails newした時のminitestは、デフォルトで並列テストを行なうようになっている。
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors) # <= ここ!!
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
Rails Guide によれば、これはDRbで実現されており、異なるRubyVMのインスタンス上で実行されるという事のようだ。
前図の理解が正しいならば、異なるRubyVMになる = ruby-debug-ide がdebaseを設定していないVMになる、ということで、breakpointが効かない。
というか、コントローラーには数件のテストがあるはずなのに、
Ruby Test Explorerのログ上は、全0件で成功0件…といったような情報が返ってしまっているように見える。
試行錯誤
可能なら「Test Explorerからの通常実行のときはparallelizeが効き、デバッグ実行のときはシングルで動く」ようにしたい。
が、結論から言うと難しかった。
環境変数で…
たとえば、与えるコマンドを指定する設定があるので、環境変数で切り替えられるかと思ったが…
parallelize(workers: :number_of_processors) unless ENV['TEST_SERIAL'].present?
{
"rubyTestExplorer.minitestCommand": "TEST_SERIAL=1 ./bin/rake"
}
これは通常実行の時のコマンドを指定するもので、
デバッグアイコンを実行すると、結果はこうなってしまう。
[2020-11-06 17:34:09.425] [INFO] Debugging test(s) ["controllers"] of /.................
[2020-11-06 17:34:09.425] [INFO] Running Ruby tests ["controllers"]
[2020-11-06 17:34:09.425] [INFO] Starting the debug session
[2020-11-06 17:34:09.426] [INFO] Running test file: /............../test/controllers/posts_controller_test.rb
[2020-11-06 17:34:09.426] [INFO] Running command: rdebug-ide --host 127.0.0.1 --port 1234 -- $EXT_DIR/debug_minitest.rb 'test/controllers/posts_controller_test.rb'
...
残念ながら、Ruby Test Explorerはdebugのときのコマンドはカスタマイズできない。
processがダメならthreadで
parallelize(workers: :number_of_processors, with: :threads)
Threadなら同じRubyVMで動くはず…と思ったが、どうやらダメ。
暫定的な対処
結局、並列実行を完全に捨ててしまえば解決はする。
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
# parallelize(workers: :number_of_processors) # <= comment out or delete this line.
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end