Help us improve
Share bugs, ideas, or general feedback.
From majestic-rails
Writes Minitest tests for Ruby and Rails apps using traditional/spec styles, fixtures, mocking, and integration patterns. Use when creating test files or testing features.
npx claudepluginhub majesticlabs-dev/majestic-marketplace --plugin majestic-railsHow this skill is triggered — by the user, by Claude, or both
Slash command
/majestic-rails:minitest-coderThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
- **AAA Pattern**: Arrange-Act-Assert structure for clarity
Writes RSpec tests for Ruby and Rails apps using AAA pattern, describe/context blocks, subject/let, fixtures, allow/expect mocking, and shoulda matchers. Use for spec files, test cases, or new features.
Enforces TDD with Minitest for Rails: fixtures, model/controller tests, WebMock HTTP mocking, integration tests; rejects RSpec/system tests.
Assists writing, reviewing, and improving RSpec tests for Ruby on Rails apps including model, controller, system, and integration specs using Better Specs and thoughtbot best practices.
Share bugs, ideas, or general feedback.
| Style | Best For | Syntax |
|---|---|---|
| Traditional | Simple unit tests | test "description" |
| Spec | Complex scenarios with contexts | describe/it with let/subject |
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
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/ - Model unit teststest/services/ - Service object teststest/integration/ - Full-stack teststest/mailers/ - Mailer teststest/jobs/ - Background job teststest/fixtures/ - Test datatest/test_helper.rb - Configurationapp/models/user.rb → test/models/user_test.rbclass Users::ProfileServiceTestrequire 'test_helper' (auto-imported)See references/spec-patterns.md for detailed examples.
| Pattern | Use Case |
|---|---|
subject { ... } | Method under test |
let(:name) { ... } | Lazy-evaluated data |
describe "context" | Group related tests (max 3 levels) |
before { ... } | Complex setup |
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: alice@example.com
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
See references/spec-patterns.md for detailed examples.
| Method | Purpose |
|---|---|
Object.stub :method, value | Stub return value |
Minitest::Mock.new | Verify method calls |
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
# 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)
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
Spec style with subject:
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
| Type | Test For |
|---|---|
| Models | Validations, associations, scopes, callbacks, methods |
| Services | Happy path, sad path, edge cases, external integrations |
| Controllers | Status codes, redirects, parameter handling |
| Jobs | Execution, retry logic, error handling |
class UserTest < ActiveSupport::TestCase
# Validations
test "validates presence of name" do
user = User.new(email: "test@example.com")
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
See references/advanced-patterns.md for production-tested patterns from 37signals.
| Pattern | Problem Solved |
|---|---|
| Current.account fixtures | Multi-tenant URL isolation |
| Assertion-validating helpers | Early failure with clear messages |
| Deterministic UUIDs | Predictable fixture ordering |
| VCR timestamp filtering | Reusable API cassettes |
| Thread-based concurrency | Race condition detection |
| Adapter-aware helpers | SQLite/MySQL compatibility |
See references/anti-patterns.md for detailed examples.
| Anti-Pattern | Why Bad |
|---|---|
require 'test_helper' | Auto-imported |
| >3 nesting levels | Unreadable output |
@ivars instead of let | State leakage |
Missing subject | Repetitive code |
assert x.include?(y) | Use assert_includes |
| Testing private methods | Implementation coupling |
| Not using fixtures | Slow tests |
Organization:
require 'test_helper'Style Choice:
Test Data:
let for shared datasubject for method under testAssertions:
assert_changes, assert_difference)Coverage:
Traditional: Simple validations, straightforward tests, no shared setup
Spec: Multiple contexts, lazy evaluation needed, nested scenarios, reusable subject
Can mix both in the same file if it improves clarity.