Testing tools in the Minitest world

In Chapter 1 you already ran tests and saw green output. In Chapter 2 you saw where tests live (test/models/, test/integration/, test/system/, and the rest).

This chapter is about what the tools are called and what each one does. When you open a test file in Chapter 5, names like Minitest, fixtures, and Capybara will make sense.

This chapter is mostly reading and vocabulary. You do not need to change the Recipes app yet.

What you will know by the end #

You should be able to answer these in your own words:

  1. What Minitest does in a Rails app and what test/test_helper.rb is for.
  2. What fixtures are and why the guide prefers them over other test data libraries/gems.
  3. What Capybara and Selenium do for system tests, and why they stay in the group :test block in the Gemfile.
  4. When WebMock or VCR are worth adding, and why we do not reach for them on day one.
  5. Which tool lines up with which folder from Chapter 2.

The default stack at a glance #

Rails 8 ships a small, opinionated test stack. This guide sticks to it unless a later chapter says otherwise.

Tool Job in one sentence Where you meet it
Minitest Runs tests, counts passes and failures, provides assert_* helpers Every file under test/
Rails Test Helpers Rails extras on top of Minitest (fixtures, HTTP helpers, mailer and job helpers) Loaded from test/test_helper.rb
Fixtures Sample records (written in YAML) loaded into the test database before tests run test/fixtures/, used from model and HTTP tests
Capybara Ruby gem that drives system tests like a person in a browser: open pages (visit), click links and buttons (click_on), type into fields (fill_in), and check what appears on screen (assert_text, assert_selector) System tests under test/system/
Selenium Opens and controls the real browser behind Capybara. Rails defaults to Chrome (often headless); you can switch to Firefox or another browser in config Wired in test/application_system_test_case.rb

We will add WebMock and VCR only when Recipes talks to the outside network and we need tests to stay offline in CI. That is a later chapter, not part of the default kit.

Minitest #

Minitest is the test framework Rails uses by default. You do not pick it in a menu when you generate an app. It is already there.

A test file is plain Ruby plus a few conventions:

  • The file ends with _test.rb (for example recipe_test.rb).
  • A class inherits from a Rails base class (for example ActiveSupport::TestCase for models).
  • Each example lives in a method that starts with test " (for example test "requires a title" do).

Minitest runs those methods, collects assertions, and prints a summary. You saw that summary in Chapter 1: runs, assertions, failures, errors, skips.

test/test_helper.rb #

Open test/test_helper.rb in the Recipes app. Almost every test file starts with:

require "test_helper"

That file boots the test environment (not development), loads Rails, and pulls in rails/test_help. Think of it as the front door for the whole suite. If a test file forgets this line, you get confusing constant errors instead of a clear test failure.

Rails also sets up things like “parallel test workers” here on many apps. You do not need to tune that yet. It is enough to know that test_helper.rb is shared setup, not a place for business logic.

Assertions you will see first #

An assertion is a line that checks something and makes the test pass or fail. Chapter 2 introduced the idea of assertions. This table is your cheat sheet: syntax (how to write it) and plain meaning (what it checks). Chapter 5 is where you first type most of these yourself.

Minitest (model and general)

Syntax Plain meaning
assert condition condition must be true (for example assert recipe.valid?)
assert_not condition condition must be false (for example assert_not recipe.valid?)
assert_equal expected, actual expected and actual must match. Order matters: expected first, actual second
assert_not_equal expected, actual Two values must differ
assert_includes collection, item collection (Array, String, or similar) must include item
assert_not_includes collection, item collection must not include item

HTTP (integration / controller style, after get, post, patch, or delete)

Syntax Plain meaning
assert_response :success Last response was a 2xx success (often 200)
assert_response :redirect Last response was a redirect (3xx)
assert_response :unprocessable_entity Last response was 422 (common for validation errors on forms)
assert_redirected_to url Last response redirected to url (use recipe_url(recipe), not only a path string)
assert_match pattern, string string must match pattern (regex or substring in practice)
assert_difference("Model.count", n) { ... } Inside the block, the row count must change by n (use 1 for create, -1 for destroy)
assert_no_difference("Model.count") { ... } Row count must stay the same inside the block
assert_no_match pattern, string string must not match pattern (for example filtered list must not include a row title)

Capybara (system tests, after visit)

Syntax Plain meaning
visit url Open url in the test browser
fill_in "Label", with: "text" Type into the field with that label (or id / name)
click_on "Button text" Click a link or button with that visible text
assert_selector "css" Page contains a matching element (for example "h1")
assert_text "copy" Visible page text includes this string
assert_no_text "copy" That string must not appear on the page
assert_current_path "/path" Browser URL path matches
accept_confirm { ... } Click inside the block and accept the browser confirm dialog
assert_no_link "text" No link with that text on the page
assert_no_button "text" No button with that text on the page

Chapter 1 uses visit and assert_current_path first; Chapter 5 adds assert_selector; Chapter 7 adds fill_in, click_on, and assert_text.

Mail and jobs (later chapters)

Syntax Plain meaning
assert_emails n { ... } Exactly n emails sent during the block
assert_enqueued_with(job: MyJob) { ... } Block must enqueue that job

The full Minitest list is in the Rails testing guide. You do not memorize every helper. You look up the row you need when a scenario calls for it.

Fixtures #

Fixtures are sample records for your models (or database tables). You define them in YAML files under test/fixtures/. Before tests run, Rails loads those records into the test database so your tests start from a known world instead of an empty database every time.

You will write real recipe fixtures in Chapter 6 but here is one example:

# test/fixtures/recipes.yml
pancakes:
  title: Fluffy pancakes

In a test, Rails exposes that record as a method:

recipes(:pancakes)

Why fixtures for this guide?

  • They ship with Rails. No extra gem to install or explain on day one. This is the main reason.
  • They keep data visible in YAML. Open test/fixtures/ and you see every sample record in one place. You do not have to dig through test files to find where data was created.
  • They work well with transactional fixtures (see Tip in Chapter 2 under Model tests): each test rolls back database changes so fixture records stay consistent from test to test.
  • They support associations between models. Child rows reference parents by fixture label in YAML (Chapter 9); user-owned recipes use the same pattern in Chapter 11.

Other guides often use Factory Bot gem (Ruby objects that build records). Factories are popular and fine. This guide defers them on purpose so you learn one predictable default first.

Capybara and Selenium (system tests) #

System tests need a real browser. That takes two gems working together:

  • Capybara

    You write the test steps in Ruby (visit, fill_in, click_on, assert_text, assert_selector) as if a person were using the site. Integration tests use get and post instead; Capybara is only for system tests when you need the real UI.

  • Selenium

    Runs the actual browser (Chrome by default) so Capybara’s steps can happen on a real page.

Your system tests inherit from ApplicationSystemTestCase, which connects Capybara to Selenium. Chrome is the default (usually headless, meaning no visible window). That is what most Rails apps use in CI and on your laptop. You can point Selenium at Firefox or another browser by changing the using: option in test/application_system_test_case.rb (for example using: :firefox). You do not need to change that for this guide.

You write Capybara calls inside the test:

visit recipes_url
assert_selector "h1"

Capybara is not for model tests. If you see visit in test/models/, something is in the wrong folder.

Docs: Capybara. Rails wires it under system testing.

NOTE: System tests are slower and need a working browser install. Capybara is powerful; you still default to model or HTTP tests when they can catch the same bug.

WebMock and VCR #

Some Recipes features will call other people’s servers: nutrition APIs, payment gateways, webhooks. In tests you usually do not want real network calls. They are slow, flaky, and need secrets (passwords/API keys).

Two common tools:

Gem Idea Good for
WebMock Block or stub HTTP at the Ruby HTTP client layer “This URL must never hit the network in test”
VCR Record a real response once, replay it in later runs “Keep a stable sample JSON on disk”

We introduce them together in a later chapter when Recipes grows external boundaries. Your Gemfile stays small until a test actually needs to fake the network.

Until then, if a test needs the network, that is a smell: stub the boundary, move the logic behind a small Ruby object, or save the example for the mock chapter.

What this guide does not use (on purpose) #

You will see these in other blog posts but we skip them here so the path stays one straight line:

Name Why not in the default path
RSpec Different syntax (describe, expect). Rails defaults to Minitest; this guide follows that default.
Factory Bot Extra gem and patterns. Fixtures first; you can adopt factories later if your team uses them.
Cucumber / Gherkin Another layer of files and vocabulary. Scenarios in this guide stay plain English in prose, then Ruby in tests.

None of that is a judgment on those tools. They are just not the spine of this guide.

Map tools back to Chapter 2 folders #

Quick recap of test folders and tools mapping:

Folder Main tools involved
test/models/ Minitest, fixtures (later), test database
test/controllers/ or test/integration/ Minitest, get / post, assert_response, fixtures when needed
test/system/ Minitest, Capybara, Selenium, fixtures when needed
test/mailers/ Minitest, Action Mailer test helpers (later chapter)
test/jobs/ Minitest, Active Job test helpers (later chapter)

When you are unsure which tool applies, ask what the scenario needs: Ruby only, HTTP response, or a real browser. The tool follows from that answer.

You now have a clear toolbox for deciding what to use and when, instead of picking test tools by guesswork.

A clear toolbox beats guesswork.

Knowing which tool fits which question stops a lot of second-guessing in later chapters. If this reference helped, fund the next chapter and keep the guide free.

One-time support via Stripe. No account required.

What is next #

You now know what the main tools do: Minitest and test_helper, fixtures for test data, Capybara and Selenium for the browser, and when to reach for HTTP fakes later.

Chapter 4 teaches scenario building and manual testing with no new app code. Chapter 5 is where you use this toolbox: Recipe scaffold, red then green model test, integration tests for HTTP, and one system smoke test.

Continue to How to approach testing.

Something unclear in this chapter?

Send feedback

Disclaimer: This guide is written in tandem with AI but reviewed and enhanced by me based on my experience with Rails and testing. I stand by the advice and patterns here.