Skip to content
Skills Library
Programming · Testing

testing-patterns

/testing-patterns

Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).

Licence
MIT
Last repository change
01.06.2026

Assessment and security

100/ 100Class: good
Format25 / 25
Frontmatter with name and description, valid name, description up to 1,024 characters, name matching the folder.
Discoverability25 / 25
Description explains when to use the skill, has a reasonable length and uses third person.
Content35 / 35
At least 150 words and at most 500 lines, headings, step lists, examples or code.
Hygiene15 / 15
No placeholders such as TODO, no Windows paths, with a licence.
Riskno signals detected in the scan
Files in this package
4
Scripts
0
HTML comments
0
URLs in SKILL.md
0
Deprecation

No signals detected. Repository changed on 01.06.2026, without references to retired models or APIs.

Licence

MIT, open: use and modify while retaining author attribution.

What it does and when to use it

Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).

Original author description

Writes Minitest tests with fixtures following 37signals conventions. Uses Minitest (not RSpec) and fixtures (not factories). Use when writing tests, adding test coverage, or creating fixtures. WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures exclusively). For test configuration/CI setup (see project docs).

How it works

  1. Your role
  2. Core philosophy
  3. Project knowledge
  4. Commands
  5. Model test structure
  6. Integration test structure
  7. Test helpers
  8. Common assertion patterns
  9. Anti-patterns to avoid
  10. Boundaries
Original SKILL.md headings · 200 lines, 615 words
SKILL.md preview
---
name: testing-patterns
description: >-
  Writes Minitest tests with fixtures following 37signals conventions. Uses
  Minitest (not RSpec) and fixtures (not factories). Use when writing tests,
  adding test coverage, or creating fixtures.
  WHEN NOT: For RSpec or FactoryBot patterns (this project uses Minitest + fixtures
  exclusively). For test configuration/CI setup (see project docs).
license: MIT
compatibility: Ruby 3.3+, Rails 8.0+, Minitest
---

You are an expert Rails testing architect specializing in Minitest with fixtures.

## Your role

- Write tests using Minitest, never RSpec
- Use fixtures for test data, never factories (FactoryBot)
- Write integration tests over unit tests when possible
- Output: Fast, readable tests that verify behavior, not implementation

## Core philosophy

**Minitest is plenty. Fixtures are faster.**

### Why Minitest: Plain Ruby (no DSL), faster suite, simpler setup, part of Rails, easier to debug.
### Why fixtures: 10-100x faster (loaded once), shared consistency, force realistic data, no factory DSL.

### Test pyramid:
- Few system tests (Capybara, full browser)
- Many integration tests (controller + model)
- Some unit tests (complex model logic only)

## Project knowledge

**Tech Stack:** Minitest 5.20+, Rails 8.2, YAML fixtures
**Location:** `test/models/`, `test/controllers/`, `test/system/`, `test/integration/`

## Commands

- `bin/rails test` -- Full suite
- `bin/rails test test/models/card_test.rb` -- Specific file
- `bin/rails test test/models/card_test.rb:14` -- Specific line
- `bin/rails test:system` -- System tests
- `bin/rails test:parallel` -- Parallel execution

## Model test structure

```ruby
require "test_helper"

class CardTest < ActiveSupport::TestCase
  setup do
    @card = cards(:logo)
    @user = users(:david)
    Current.user = @user
    Current.account = @card.account
  end

  teardown do
    Current.reset
  end

  test "fixtures are valid" do
    assert @card.valid?
  end

  test "closing card creates closure record" do
    assert_difference -> { Closure.count }, 1 do
      @card.close(user: @user)
    end
    assert @card.closed?
    assert_equal @user, @card.closed_by
  end

  test "open scope excludes closed cards" do
    @card.close
    assert_not_includes Card.open, @card
    assert_includes Card.closed, @card
  end
end
```

## Integration test structure

```ruby
require "test_helper"

class CardsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @card = cards(:logo)
    sign_in_as users(:david)
  end

  test "should create card" do
    assert_difference -> { Card.count }, 1 do
      post board_cards_path(@card.board), params: {
        card: { title: "New card", column_id: @card.column_id }
      }
    end
    assert_redirected_to card_path(Card.last)
  end

  test "requires authentication" do
    sign_out
    get card_path(@card)
    assert_redirected_to new_session_path
  end
end
```

## Test helpers

```ruby
# test/test_helper.rb
class ActionDispatch::IntegrationTest
  def sign_in_as(user)
    session_record = user.identity.sessions.create!
    cookies.signed[:session_token] = session_record.token
    Current.user = user
    Current.identity = user.identity
    Current.session = session_record
  end

  def sign_out
    cookies.delete(:session_token)
    Current.reset
  end
end

class ActiveSupport::TestCase
  fixtures :all
  parallelize(workers: :number_of_processors)
end
```

## Common assertion patterns

```ruby
# Record count changes
assert_difference -> { Card.count }, 1 do ... end

# Attribute updates
@card.close
assert @card.closed?
assert_equal @user, @card.closed_by

# Errors
assert_raises ActiveRecord::RecordInvalid do
  Card.create!(title: nil)
end

# Collections
assert_includes Card.open, @card
refute_includes Card.closed, @card

# HTTP responses
assert_response :success
assert_redirected_to card_path(Card.last)

# DOM assertions
assert_select "h1", "Cards"
assert_select ".card", count: 3

# Jobs and emails
assert_enqueued_with job: NotifyRecipientsJob do ... end
assert_emails 1 do ... end
```

## Anti-patterns to avoid

```ruby
# BAD: Using factories
let(:card) { FactoryBot.create(:card) }
# GOOD: Use fixtures
setup { @card = cards(:logo) }

# BAD: Testing implementation
test "calls create_closure" do
  @card.expects(:create_closure!)
  @card.close
end
# GOOD: Test behavior
test "closing creates closure" do
  @card.close
  assert @card.closed?
end

# BAD: Creating data when fixtures exist
setup { @user = User.create!(name: "Test") }
# GOOD: Use fixtures
setup { @user = users(:david) }

# BAD: Testing Rails functionality
test "validates presence of title" do ...
# GOOD: Only test custom validations
test "validates title doesn't contain profanity" do ...
```

## Boundaries

- **Always:** Use Minitest, use fixtures, test behavior not implementation, write integration tests for features, use descriptive test names, clean up in teardown
- **Ask first:** Before testing private methods (test public interface), before testing Rails functionality (already tested), before using mocks/stubs (prefer real objects)
- **Never:** Use RSpec, use FactoryBot, test implementation details, create unnecessary test data, skip system tests for critical features

## Reference files

- `references/fixture-patterns.md` -- YAML fixture patterns, ERB, UUID fixtures, associations
- `references/controller-tests.md` -- Controller/integration test patterns, Turbo Stream assertions
- `references/system-tests.md` -- Capybara system test patterns, setup, assertions
Files in this package (4)
  • SKILL.md 5 KB
  • references/controller-tests.md 5 KB
  • references/fixture-patterns.md 4 KB
  • references/system-tests.md 5 KB

Versions

RepositoryScoreLicence
This page · ThibautBaissac/rails_ai_agents100MIT
Reprograme/redevkit100MIT
piomin/claude-ai-spring-boot100Apache-2.0
FrancoStino/opencode-skills-collection100MIT
rootcastleco/rei-skills100MIT
davila7/claude-code-templates100MIT
svngoku/coding-agents-skills100MIT
organvm-iv-taxis/a-i--skills100Apache-2.0
leather-io/mono100MIT

Database snapshot: 13.11.2026 · package version 6a6a8f03b96a (SHA-256 digest of the entire package)

Downloads in the last 30 days: 0 · ranking

Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.

Similar skills

  • 81rails-ai:testing
    Use when testing Rails applications - TDD, Minitest, fixtures, model testing, mocking, test helpers
  • 100tdd
    Test-driven development and testing patterns for Rails applications. Drives implementation from tests using an outside-in approach with RSpec, Capybara, and FactoryBot. Use when building new features, writing or improving tests, adding test coverage, fixing bugs with a…
  • 100spree-testing
    Use when the user is writing or running automated tests for a Spree 6 app or extension — model specs, workflow/hook specs, subscriber specs, API v3 controller/request specs, factories, and dashboard (Vitest/Playwright) tests. Covers RSpec + Factory Bot (not Minitest/fixtures),…
  • 95rails-cto-minitest
    Write and maintain Minitest tests for a Rails 8 application using the Minitest::Spec DSL. Covers model tests, command/service tests, controller/integration tests, job tests, ViewComponent tests, and system tests. Use this skill whenever writing, fixing, or reviewing tests, or…
  • 100jitcatch
    Use when reviewing or landing a code change and you want throwaway tests that catch regressions it introduces. Drives the jitcatch CLI (context, run, assess) for a Ruby diff. Write Minitest or RSpec files that pass on the base revision and fail on head, drop flakes, then judge…
  • 100branchout
    Explore concrete inputs that reach uncovered Ruby branch arms and emit minitest or RSpec characterization tests. Use when adding tests for under-covered Ruby branches, when exploring inputs that reach an uncovered if/unless/case/while arm, or when a Ruby method's branch coverage is still incomplete.

Feedback and reports

Your message goes to Bartosz Sokoliński. An email address is needed only for a reply. See the privacy policy.