RSpec with Railsでテスト時のデータはどのように削除されているか
RailsアプリでRSpecを使うと通常example実行のたびにデータが削除されるようになっているが、これが具体的にどのように行われているかについて。
検証環境は以下の通り。
- ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin16]
- rails 5.2.2
- rspec 3.8.0
- rspec-rails 3.8.2
- SQLite 3.16.0
use_transactional_fixtures
RailsでRspecを使うとき、 bundle exec rails generate rspec:install
を実行して初期設定をすることになると思うが、そのときに spec/rails_helper.rb
という設定ファイルも同時に作られる。
このファイルにデフォルトで次のような設定が記載されている。
RSpec.configure do |config|
# ..省略
config.use_transactional_fixtures = true
# ..省略
end
この use_transactional_fixtures
という設定項目が true になっていると、exampleのたびにデータが削除されるようになる。
削除の仕組み
use_transactional_fixtures
という設定名からは想像がつきにくいのだが、1つのexampleがデータベースのトランザクションの中で実行されるようになり、exampleの終わりにロールバックされ、データが消えるという仕組みになっている。
テストを実行したときの log/test.log を見るとその様子がよくわかる。
(0.1ms) begin transaction
(0.1ms) SAVEPOINT active_record_1
// ここでexampleが実行。テスト内容に応じた各種SQLが出力される
(0.1ms) RELEASE SAVEPOINT active_record_1
(0.5ms) rollback transaction
exampleの実行前に begin transaction
、終わりに rollback transaction
というログが出力されている。
before(:each) と before(:all)
これは本題とは関係無いが、関連知識として知っておいた方が良いと思ったのでついでに書く。
before(:each)
ブロックに書いた事前処理は先のrollbackの対象となり、明示的に削除処理を書かなくても自動で削除される。- 一方、
before(:all)
ブロックに書いた事前処理はtransactionの外側で実行されるため自動では削除されない。必要に応じて明示的に事後処理を書く必要がある。
Tips
use_transactional_fixtures
のエイリアスとして、use_transactional_examples
も使えるようになっている。
https://github.com/rspec/rspec-rails/blob/5a9182b24c7370ba293fcdd13d7ce01e6d24cd2e/lib/rspec/rails/configuration.rb#L65
こちらの方が名前としてわかりやすいね。