minitest-coder について
minitest-coderは、RailsプロジェクトでMinitestのテストを書く方法をまとめたスキルガイドです。テスト形式、フィクスチャ、アサーション、カバレッジに加え、テストを整理しやすく保つパターンを扱います。
主な機能
- 01従来型とspec形式のテスト
- 02AAA構造と振る舞い重視のテスト
- 03Railsのテストファイル構成
- 04フィクスチャ、スタブ、モック
- 05アサーションとカバレッジの指針
- 06応用パターンとアンチパターン
活用シーン
- 01Railsのモデルやサービスのテスト作成
- 02シナリオに合うMinitest形式の選択
- 03テスト構成とカバレッジの確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ majesticlabs-dev/ majestic-marketplace --skill minitest-coderインストール後、Claude Code で/minitest-coderを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/advanced-patterns.mdanti-patterns.mdspec-patterns.mdtesting-tips.md詳細
Minitest コーダー
基本理念
- AAA パターン:明確さを重視した Arrange-Act-Assert 構造
- 実装より振る舞い:コードの実装方法ではなく、動作をテストします
- 分離:テストはそれぞれ独立させます
- 説明的な名前:テストの内容が明確に分かる名前を付けます
- カバレッジ:正常系とエッジケースの両方をテストします
- 高速なテスト:データベース操作を最小限にします
- フィクスチャ:テストデータにはフィクスチャを使用します
Minitest のスタイル
| スタイル | 最適な用途 | 構文 |
|---|---|---|
| 従来型 | シンプルな単体テスト | test "description" |
| Spec | コンテキストを含む複雑なシナリオ | let/subjectを使ったdescribe/it |
従来型スタイル
class UserTest < ActiveSupport::TestCase
test "validates presence of name" do
user = User.new
assert_not user.valid?
assert_includes user.errors[:name], "can't be blank"
end
end
Spec スタイル
class UserTest < ActiveSupport::TestCase
describe "#full_name" do
subject { user.full_name }
let(:user) { User.new(first_name: "Buffy", last_name:) }
describe "with last name" do
let(:last_name) { "Summers" }
it "returns full name" do
assert_equal "Buffy Summers", subject
end
end
end
end
テストの構成
ファイル構成
test/models/- モデルの単体テストtest/services/- サービスオブジェクトのテストtest/integration/- フルスタックテストtest/mailers/- メーラーのテストtest/jobs/- バックグラウンドジョブのテストtest/fixtures/- テストデータtest/test_helper.rb- 設定
命名規則
- アプリの構成を反映します:
app/models/user.rb→test/models/user_test.rb - 完全修飾名前空間を使用します:
class Users::ProfileServiceTest require 'test_helper'は追加しないでください(自動で読み込まれます)
Spec スタイルのパターン
詳しい例はreferences/spec-patterns.mdを参照してください。
| パターン | 用途 |
|---|---|
subject { ... } | テスト対象のメソッド |
let(:name) { ... } | 遅延評価されるデータ |
describe "context" | 関連するテストをまとめます(最大3階層) |
before { ... } | 複雑なセットアップ |
describe "#process" do
subject { processor.process }
let(:processor) { OrderProcessor.new(order) }
let(:order) { orders(:paid_order) }
it "succeeds" do
assert subject.success?
end
end
フィクスチャ
# test/fixtures/users.yml
alice:
name: Alice Smith
email: [email protected]
created_at: <%= 2.days.ago %>
class UserTest < ActiveSupport::TestCase
fixtures :users
test "validates uniqueness" do
duplicate = User.new(email: users(:alice).email)
assert_not duplicate.valid?
end
end
モックとスタブ
詳しい例はreferences/spec-patterns.mdを参照してください。
| メソッド | 目的 |
|---|---|
Object.stub :method, value | 戻り値をスタブします |
Minitest::Mock.new | メソッド呼び出しを検証します |
test "processes payment" do
PaymentGateway.stub :charge, true do
processor = OrderProcessor.new(order)
assert processor.process
end
end
アサーション早見表
基本的なアサーション
# Boolean
assert user.valid?
assert_not user.admin?
# Equality
assert_equal "Alice", user.name
assert_nil user.deleted_at
# Collections
assert_includes users, admin_user
assert_empty order.items
# Exceptions
assert_raises ActiveRecord::RecordInvalid do
user.save!
end
Rails のアサーション
# Changes
assert_changes -> { user.reload.status }, to: "active" do
user.activate!
end
assert_difference "User.count", 1 do
User.create(name: "Charlie")
end
# Responses
assert_response :success
assert_redirected_to user_path(user)
AAA パターン
test "processes refund" do
# Arrange
order = orders(:completed_order)
original_balance = order.user.account_balance
# Act
result = order.process_refund
# Assert
assert result.success?
assert_equal "refunded", order.reload.status
end
subject を使った Spec スタイル:
describe "#process_refund" do
subject { order.process_refund }
let(:order) { orders(:completed_order) }
it "updates status" do
subject
assert_equal "refunded", order.reload.status
end
it "credits user" do
assert_changes -> { order.user.reload.account_balance }, by: order.total do
subject
end
end
end
テストカバレッジの基準
| 種類 | テスト対象 |
|---|---|
| モデル | バリデーション、関連付け、スコープ、コールバック、メソッド |
| サービス | 正常系、異常系、エッジケース、外部連携 |
| コントローラー | ステータスコード、リダイレクト、パラメーターの処理 |
| ジョブ | 実行、再試行ロジック、エラー処理 |
カバレッジの例
class UserTest < ActiveSupport::TestCase
# Validations
test "validates presence of name" do
user = User.new(email: "[email protected]")
assert_not user.valid?
assert_includes user.errors[:name], "can't be blank"
end
# Methods
describe "#full_name" do
subject { user.full_name }
let(:user) { User.new(first_name: "Alice", last_name: "Smith") }
it "returns full name" do
assert_equal "Alice Smith", subject
end
describe "without last name" do
let(:user) { User.new(first_name: "Alice") }
it "returns first name only" do
assert_equal "Alice", subject
end
end
end
end
高度なパターン
本番環境で検証済みの37signalsのパターンについては、references/advanced-patterns.mdを参照してください。
| パターン | 解決する問題 |
|---|---|
| Current.account フィクスチャ | マルチテナント環境での URL 分離 |
| アサーション検証ヘルパー | 明確なメッセージを伴う早期失敗 |
| 決定的な UUID | 予測可能なフィクスチャの順序 |
| VCR のタイムスタンプフィルタリング | 再利用可能な API カセット |
| スレッドベースの並行処理 | 競合状態の検出 |
| アダプター対応ヘルパー | SQLite/MySQL との互換性 |
アンチパターン
詳しい例はreferences/anti-patterns.mdを参照してください。
| アンチパターン | 問題点 |
|---|---|
require 'test_helper' | 自動で読み込まれます |
| 3階層を超えるネスト | 出力が読みにくくなります |
letの代わりに@ivarsを使う | 状態が漏洩します |
subjectがない | コードが重複します |
assert x.include?(y) | assert_includesを使ってください |
| プライベートメソッドのテスト | 実装との結合が強まります |
| フィクスチャを使わない | テストが遅くなります |
ベストプラクティスのチェックリスト
構成:
- ファイル構成がアプリの構成を反映している
-
require 'test_helper'を追加していない - 完全修飾名前空間を使用している
スタイルの選択:
- シンプルなテストには従来のスタイルを使用している
- 複雑なコンテキストには Spec を使用している
- ネストは最大 3 階層にしている
テストデータ:
- フィクスチャを使用している(ファクトリーではなく)
- 共通データに
letを使用している - テスト対象のメソッドに
subjectを使用している
アサーション:
- 適切なアサーションメソッドを使用している
- Rails のヘルパー(
assert_changes、assert_difference)を使用している - 実装ではなく動作をテストしている
カバレッジ:
- 正常系をテストしている
- 異常系をテストしている
- エッジケースを網羅している
スタイルを選ぶ基準
従来のスタイル:シンプルなバリデーション、わかりやすいテスト、共通のセットアップがない場合
Spec:複数のコンテキスト、遅延評価が必要な場合、ネストしたシナリオ、再利用可能な subject がある場合
わかりやすさが向上する場合は、同じファイル内で両方を組み合わせることもできます。
コメント
Markdown 対応