Marketplace

minitest-coder

This skill guides writing comprehensive Minitest tests for Ruby and Rails applications. Use when creating test files, writing test cases, or testing new features. Covers both traditional and spec styles, fixtures, mocking, and Rails integration testing patterns.

allowed_tools: Read, Write, Edit, MultiEdit, Grep, Glob, Bash, WebSearch

$ インストール

git clone https://github.com/majesticlabs-dev/majestic-marketplace /tmp/majestic-marketplace && cp -r /tmp/majestic-marketplace/plugins/majestic-rails/skills/minitest-coder ~/.claude/skills/majestic-marketplace

// tip: Run this command in your terminal to install the skill


name: minitest-coder description: This skill guides writing comprehensive Minitest tests for Ruby and Rails applications. Use when creating test files, writing test cases, or testing new features. Covers both traditional and spec styles, fixtures, mocking, and Rails integration testing patterns. allowed-tools: Read, Write, Edit, MultiEdit, Grep, Glob, Bash, WebSearch

Minitest Coder

Core Philosophy

  • AAA Pattern: Arrange-Act-Assert structure for clarity
  • Behavior over Implementation: Test what code does, not how
  • Isolation: Tests should be independent
  • Descriptive Names: Clear test descriptions
  • Coverage: Test happy paths AND edge cases
  • Fast Tests: Minimize database operations
  • Fixtures: Use fixtures for test data

Minitest Styles

StyleBest ForSyntax
TraditionalSimple unit teststest "description"
SpecComplex scenarios with contextsdescribe/it with let/subject

Traditional Style

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 Style

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 Organization

File Structure

test/
├── models/           # Model unit tests
├── services/         # Service object tests
├── integration/      # Full-stack tests
├── mailers/          # Mailer tests
├── jobs/             # Background job tests
├── fixtures/         # Test data
└── test_helper.rb    # Configuration

Naming Conventions

  • Mirror app structure: app/models/user.rbtest/models/user_test.rb
  • Use fully qualified namespace: class Users::ProfileServiceTest
  • Don't add require 'test_helper' (auto-imported)

Spec Style Patterns

See resources/spec-patterns.md for detailed examples.

PatternUse 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

Fixtures

# 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

Mocking and Stubbing

See resources/spec-patterns.md for detailed examples.

MethodPurpose
Object.stub :method, valueStub return value
Minitest::Mock.newVerify method calls
test "processes payment" do
  PaymentGateway.stub :charge, true do
    processor = OrderProcessor.new(order)
    assert processor.process
  end
end

Assertions Quick Reference

Basic Assertions

# 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 Assertions

# 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 Pattern

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

Test Coverage Standards

TypeTest For
ModelsValidations, associations, scopes, callbacks, methods
ServicesHappy path, sad path, edge cases, external integrations
ControllersStatus codes, redirects, parameter handling
JobsExecution, retry logic, error handling

Coverage Example

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

Advanced Patterns

See resources/advanced-patterns.md for production-tested patterns from 37signals.

PatternProblem Solved
Current.account fixturesMulti-tenant URL isolation
Assertion-validating helpersEarly failure with clear messages
Deterministic UUIDsPredictable fixture ordering
VCR timestamp filteringReusable API cassettes
Thread-based concurrencyRace condition detection
Adapter-aware helpersSQLite/MySQL compatibility

Anti-Patterns

See resources/anti-patterns.md for detailed examples.

Anti-PatternWhy Bad
require 'test_helper'Auto-imported
>3 nesting levelsUnreadable output
@ivars instead of letState leakage
Missing subjectRepetitive code
assert x.include?(y)Use assert_includes
Testing private methodsImplementation coupling
Not using fixturesSlow tests

Best Practices Checklist

Organization:

  • Files mirror app structure
  • NOT adding require 'test_helper'
  • Using fully qualified namespace

Style Choice:

  • Traditional for simple tests
  • Spec for complex contexts
  • Max 3 nesting levels

Test Data:

  • Using fixtures (not factories)
  • Using let for shared data
  • Using subject for method under test

Assertions:

  • Correct assertion methods
  • Rails helpers (assert_changes, assert_difference)
  • Testing behavior, not implementation

Coverage:

  • Happy path tested
  • Sad path tested
  • Edge cases covered

When to Choose Style

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.

Repository

majesticlabs-dev
majesticlabs-dev
Author
majesticlabs-dev/majestic-marketplace/plugins/majestic-rails/skills/minitest-coder
13
Stars
0
Forks
Updated6d ago
Added1w ago