Agent Skills: Minitest Coder

Write Minitest tests for Ruby and Rails applications. Use when creating test files, writing test cases, or testing new features. Not for RSpec — use rspec-coder instead. Covers both traditional and spec styles, fixtures, mocking, and Rails integration testing patterns.

UncategorizedID: majesticlabs-dev/majestic-marketplace/minitest-coder

Install this agent skill to your local

pnpm dlx add-skill https://github.com/majesticlabs-dev/majestic-marketplace/tree/HEAD/plugins/majestic-rails/skills/minitest-coder

Skill Files

Browse the full folder contents for minitest-coder.

Download Skill

Loading file tree…

plugins/majestic-rails/skills/minitest-coder/SKILL.md

Skill Metadata

Name
minitest-coder
Description
Write Minitest tests for Ruby and Rails applications. Use when creating test files, writing test cases, or testing new features. Not for RSpec — use rspec-coder instead. Covers both traditional and spec styles, fixtures, mocking, and Rails integration testing patterns.

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

| Style | Best For | Syntax | |-------|----------|--------| | Traditional | Simple unit tests | test "description" | | Spec | Complex scenarios with contexts | describe/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
  • test/services/ - Service object tests
  • test/integration/ - Full-stack tests
  • test/mailers/ - Mailer tests
  • test/jobs/ - Background job tests
  • test/fixtures/ - Test data
  • test/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 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

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

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

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

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

Anti-Patterns

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 |

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.