この記事はRuby Advent Calendar 2022の12/6の記事です。
最近、Ruby on Railsを使って初めて1からWebシステムを作っている。 Railsではデフォルトで*1Minitestのテストコードが生成される。 システムを作成しはじめた当初はデフォルトであるMinitestで書いていたのだが、作業を進めていくうえでRspecのようにテストのコンテキストによりテストコードをブロックで分けたほうが書きやすいと思い始めてきた。 調べるとどうやらMinitest::SpecでRSpec風に書けることがわかったので、備忘録的にブログに残しておく。
Minitest::Spec
公式ドキュメントに書いてあるとおりrequire "minitest/autorun"
するだけでよい。便利。
contextとdescribed_classが使えない
Rspecを使ったことがあると、Minitest::Specを使うとcontextとdescribed_classが使えないことに気が付く。 contextを使いたい場合は minitest-spec-contextを使うと便利だった。 あまり開発が活発ではないGemだが、そもそもコードがシンプルなのでそういうものだと思う。 described_classも使えないのだが、良い感じのGemが見つからなかったのでこれは使わない方法で書いている。
Railsで使う場合はminitest-railsを使う
RailsでMinitest::Specを使う場合は minitest-rails
を使うとよい。
Railsのバージョンによって、minitest-railsのバージョンが違うので注意が必要だ。
ここではRail 7系を想定している。
# Gemfile group :test do gem 'minitest-rails', '~> 7.0' end
そしてtest_helper.rbあたりにrequire 'minitest/rails'
しておくとよい。
require_relative '../config/environment' require 'rails/test_help' require 'minitest/rails' # ここを追加
ここからは必須設定ではないのだが、以下の設定をするとrails g
したときに生成されるテストコードもMinitest::Specにすることができる。
# config/application.rb module SampleApplication class Application < Rails::Application # 以下を追加 config.generators do |g| g.test_framework :minitest, spec: true end end end
rails g
すると以下のようなテストコードが生成される。
❯ cat test/models/example_test.rb require "test_helper" describe Example do # it "does a thing" do # value(1+1).must_equal 2 # end end
MinitestからMinitest::Specに書き換えてみた
実際に私が書き換えたテストコードを並べてみる。
# Minitestで書いたテストコード class FooBarTest < ActiveSupport::TestCase test 'search_by_keywordに空のクエリを渡すと空の結果が返ってくること' do query = { keyword: nil, enabled: false, disabled: false, registered: false, unregistered: false } got = FooBar.search_by_keyword(query) assert_equal [], got end test 'search_by_keywordにキーワードを渡すと名前で検索されること' do query = { keyword: 'てすと', enabled: false, disabled: false, registered: false, unregistered: false } got = FooBar.search_by_keyword(query).map { |s| s.name }.sort assert_equal %w[てすと1 てすと2 てすと3 てすと4 てすと5], got end end # Minitest::Specで書いたテストコード describe FooBar do describe '#search_by_keyword' do it '空のクエリを渡すと空の結果が返ってくること' do query = { keyword: nil, enabled: false, disabled: false, registered: false, unregistered: false } got = FooBar.search_by_keyword(query) assert_equal [], got end it 'キーワードを渡すと名前で検索されること' do query = { keyword: 'てすと', enabled: false, disabled: false, registered: false, unregistered: false } got = FooBar.search_by_keyword(query).map { |s| s.name }.sort assert_equal %w[てすと1 てすと2 てすと3 てすと4 てすと5], got end end
まとめ
Minitest::Specを使うことでRSpec風に書けることが分かった。 個人的にはMinitest::Specを使うとテストのコンテキストがはっきりしてわかりやすいと思う。 しかしながら、すでに書かれたMinitestで書かれたテストを書きなおすほどのメリットがあるかといわれると、どうだろうなぁという感じもある。 なので、プロジェクトや環境によって使い分けるとよさそうに思う。
*1:rails newsしたときに作られるのでそう思っている