Rails は自動テストの環境が充実しており、
CI (Continuous Integration) に向いています。
rails generate の多くでテスト用のテンプレートが生成されます。
テンプレートの作法に則ってテストを書いていくとラクです。
通常の開発であれば、
コード変更とテストコード作成はセットです。
コードを書いたら即テストして、デバッグ。
自動テストでほぼカバーできる Rails は、
デグレード・チェックも含めて時間効率が優れています。
が、
サンプルプログラムはコードの一例として書いているだけで、
テストコードの実体は殆どありません。
ご容赦ください。
\test\fixtures には、
テストで使用する、各モデル毎のデフォルト値を YAML で書きます。
例えば、
one:
enabled: true
name: こころ
isbn: "978-4101010014"
category: one
step: one
memo: MyString
のようにです。
各テスト実施毎にデータベースがこのデフォルト値になります。
YAML 上、references のカラムは、
ID の数値を直書きせずとも、参照先の YAML のラベルを書けばOKです。
category: one のように。
カラム名自体は category_id ですが、references 同様の書き方なのに留意してください。
実際のテストで使用する際は、
@book = books(:one)
のように、テーブル名(YAMLのラベル) を指定します。

YAML の定義で、ID のカラムに即値を書いても構いませんが、
書かなければ(デフォルトそうですが)、データベース登録時に適当な値が割り当てられます。
また、
通常、全てのテストで全ての YAML がデータベースに適用されます。
これは、\test\test_helper.rb で fixtures :all と書いているからです。
通常はこれで支障ないですが、
絞り込みたい場合は、
fixtures :all 部分をコメントアウトした上で、テストファイル毎に設定してください。
e.g.
●\test\test_helper.rb
module ActiveSupport
class TestCase
#fixtures :all
●\test\controllers\books_controller_test.rb
class BooksControllerTest < ActionDispatch::IntegrationTest
fixtures :books, :users
こうする場合、全てのテストファイルで fixtures を設定しないといけません。
fixtures :all を活かしたまま各ファイルに fixtures を書いても、
各ファイルの設定で上書きされるわけでは無いようです。
テストは、以下に分類されます。
後、Pundit を使う場合は、policies も追加されます。

大昔(Rails 5.0 まで?) のコントローラテストは、
class BooksControllerTest < ActionController::TestCase
のように、機能テストを継承していました。
が、現在は、
BooksControllerTest < ActionDispatch::IntegrationTest
のように、統合テストを継承しています。
つまり、controllers も integration も仕様的には全く同じですが、
用途によって人間が使い分けるということです。
参考: https://api.rubyonrails.org/classes/ActionController/TestCase.html
デフォルトでは、テストを複数のスレッドで動作させるように
\test\test_helper.rb で、
parallelize(workers: :number_of_processors, with: :threads)
と書かれています。
が、エラーになる事が多いので、
parallelize(workers: 1)
にしておくのが安全でしょう。
デフォルトでは、
RuntimeError: Could not find a valid mapping for #<User id: ・・・
ActiveRecord::ActiveRecordError: Cannot expire connection, it is owned by a different thread: #<Thread: ・・・
みたいなエラーになる事があります。
複数スレッド間での衝突が起こっていると思われます。
1つのテストファイル中に複数のテストを実装すると思います。
ファイル内共通で使える以下のメソッドが便利です。
e.g.
class BooksControllerTest < ActionDispatch::IntegrationTest
setup do
@book = books(:one)
@user = users(:admin)
sign_in @user
end
teardown do
# 必要なら書く。
end
ruby bin/rails test
で、System Test 以外 のテストが実行されます。
エラーなど無ければ、
90 runs, 133 assertions, 0 failures, 0 errors, 0 skips
のように表示されて終了します。
エラーが発生したら、その時点でテストを中断し、
エラー内容を表示するので、デバッグします。
エラーメッセージの例:
Failure:
BooksControllerTest#test_should_get_index [test/controllers/books_controller_test.rb:13]:
Expected response to be a <422: unprocessable_entity>, but was a <200: OK>
解説:テストコードでは response が unprocessable_entity になると書いているが、実際には OK だった。
指定範囲だけをテストする事も可能です。
"should get index" なら -n test_should_get_index