minitest-testing

SKILL.md

Minitest Testing for Rails

Write comprehensive, maintainable Minitest tests following Rails conventions and best practices. This skill provides patterns for model tests, controller tests, system tests with Capybara, and fixture usage.


Core Testing Principles

1. Test Structure

Organize tests with clear phases:

test "creates article with valid attributes" do
  # Arrange - set up test data
  user = users(:alice)

  # Act - perform the action
  article = Article.create(
    title: "Test Article",
    body: "Content here",
    user: user
  )

  # Assert - verify the outcome
  assert article.persisted?
  assert_equal "Test Article", article.title
end

2. Test Independence

Each test should be independent and able to run in any order. Use setup for common initialization:

class ArticleTest < ActiveSupport::TestCase
  setup do
    @user = users(:alice)
    @article = articles(:published)
  end

  test "publishes article" do
    @article.publish!
    assert @article.published?
  end
end

3. Single Responsibility

Each test verifies one behavior, though it may use multiple assertions to fully verify that behavior.


Test Types

Model Tests (test/models/)

Test business logic, validations, associations, and custom methods.

File location: test/models/article_test.rb

class ArticleTest < ActiveSupport::TestCase
  test "validates presence of title" do
    article = Article.new(body: "Content")
    assert_not article.valid?
    assert_includes article.errors[:title], "can't be blank"
  end

  test "belongs to user" do
    article = articles(:published)
    assert_instance_of User, article.user
  end

  test "#published? returns true when status is published" do
    article = articles(:published)
    assert article.published?
  end
end

Controller Tests (test/controllers/)

Test HTTP responses, redirects, authentication, and parameter handling.

File location: test/controllers/articles_controller_test.rb

class ArticlesControllerTest < ActionDispatch::IntegrationTest
  setup do
    @user = users(:alice)
    sign_in_as(@user)  # helper method
  end

  test "GET index returns success" do
    get articles_path
    assert_response :success
  end

  test "POST create with valid params creates article" do
    assert_difference("Article.count", 1) do
      post articles_path, params: {
        article: { title: "New Article", body: "Content" }
      }
    end

    assert_redirected_to article_path(Article.last)
  end

  test "POST create with invalid params renders new" do
    assert_no_difference("Article.count") do
      post articles_path, params: {
        article: { title: "", body: "" }
      }
    end

    assert_response :unprocessable_entity
  end
end

System Tests (test/system/)

Test end-to-end user workflows with browser simulation.

File location: test/system/article_creation_test.rb

class ArticleCreationTest < ApplicationSystemTestCase
  test "user creates new article" do
    visit root_path
    click_on "New Article"

    fill_in "Title", with: "My Test Article"
    fill_in "Body", with: "This is the content"
    select "Published", from: "Status"

    click_on "Create Article"

    assert_text "Article was successfully created"
    assert_text "My Test Article"
  end

  test "article updates with Turbo Frame" do
    article = articles(:draft)
    visit article_path(article)

    click_on "Edit"
    fill_in "Title", with: "Updated Title"
    click_on "Update Article"

    # Turbo Frame update - no full page reload
    assert_text "Updated Title"
    assert_no_text article.title
  end
end

Detailed Patterns & Examples

For comprehensive Minitest patterns and examples, see examples.md.

Pattern Categories

examples.md contains:

  • Fixtures - YAML fixtures, associations, and fixture access
  • Model Testing - Validations, associations, scopes, callbacks, enums
  • Controller Testing - CRUD actions, authentication, authorization
  • System Testing - Capybara selectors, form interactions, JavaScript behavior
  • Turbo/Hotwire Testing - Turbo Frames, Turbo Streams, Stimulus controllers
  • Background Jobs - Testing ActiveJob and SolidQueue jobs
  • Mailers - Testing ActionMailer delivery and content
  • Test Helpers - Custom assertions and helper methods
  • Mocking/Stubbing - When and how to use mocks with Minitest

Refer to examples.md for complete code examples.


Common Assertions

# Equality
assert_equal expected, actual
assert_not_equal unexpected, actual

# Truth/Falsehood
assert value
assert_not value
assert_nil value
assert_not_nil value

# Predicates
assert article.valid?
assert_not article.persisted?
assert articles.empty?

# Collections
assert_includes array, item
assert_empty collection
assert_not_empty collection

# Differences (counting changes)
assert_difference "Article.count", 1 do
  Article.create!(title: "New", body: "Content")
end

assert_no_difference "Article.count" do
  Article.create(title: "", body: "")  # invalid
end

# HTTP Responses
assert_response :success
assert_response :redirect
assert_response :not_found
assert_redirected_to articles_path

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

Fixtures

Fixture Files (test/fixtures/*.yml)

# test/fixtures/users.yml
alice:
  email: alice@example.com
  name: Alice Smith
  role: admin

bob:
  email: bob@example.com
  name: Bob Jones
  role: member
# test/fixtures/articles.yml
published:
  user: alice
  title: Published Article
  body: This article is live
  status: published
  published_at: <%= 1.day.ago %>

draft:
  user: bob
  title: Draft Article
  body: Work in progress
  status: draft

Using Fixtures in Tests

test "finds published articles" do
  published = articles(:published)
  draft = articles(:draft)

  results = Article.published

  assert_includes results, published
  assert_not_includes results, draft
end

Test Helpers

Authentication Helper

# test/test_helper.rb
class ActionDispatch::IntegrationTest
  def sign_in_as(user)
    post login_path, params: { email: user.email, password: "password" }
  end
end

Custom Assertions

# test/test_helper.rb
module ActiveSupport
  class TestCase
    def assert_valid(record)
      assert record.valid?, "Expected #{record.class} to be valid, errors: #{record.errors.full_messages}"
    end
  end
end

Running Tests

# Run all tests
bin/rails test

# Run specific test file
bin/rails test test/models/article_test.rb

# Run specific test by line number
bin/rails test test/models/article_test.rb:12

# Run tests by pattern
bin/rails test test/models/*_test.rb

# Run system tests only
bin/rails test:system

# Run tests in parallel
bin/rails test:parallel

# Run with verbose output
bin/rails test -v

# Run and show coverage
COVERAGE=true bin/rails test

Official Documentation:

Tools:

Weekly Installs
3
GitHub Stars
4
First Seen
14 days ago
Installed on
opencode3
gemini-cli3
github-copilot3
codex3
amp3
cline3