# Testing with Minitest and Fixtures in Maybe: Rails Patterns Explained

> Explore Minitest patterns in the maybe-finance/maybe Rails project. Learn how `fixtures :all` and `ActiveSupport::TestCase` streamline your testing for efficient development.

- Repository: [Maybe/maybe](https://github.com/maybe-finance/maybe)
- Tags: testing
- Published: 2026-03-07

---

**The maybe-finance/maybe repository uses pure Minitest with Rails conventions, automatically loading all YAML fixtures via `fixtures :all`, inheriting from `ActiveSupport::TestCase`, and running tests in parallel with processor-based workers.**

The maybe-finance/maybe project follows a strict convention-over-configuration approach for its test suite, relying entirely on Rails' default Minitest framework rather than RSpec. By examining the source code in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb) and the comprehensive fixture setup, developers can understand how the application achieves fast, deterministic testing with minimal external dependencies.

## Core Configuration in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb)

Every test file in the Maybe codebase inherits from `ActiveSupport::TestCase`, defined in the global [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb). This base class configures the fundamental testing environment including parallelization, fixture loading, and external service mocking.

```ruby

# test/test_helper.rb

class ActiveSupport::TestCase
  parallelize(workers: :number_of_processors) unless ENV["DISABLE_PARALLELIZATION"]
  fixtures :all
end

```

The `parallelize(workers: :number_of_processors)` setting enables parallel test execution across all available CPU cores unless the `DISABLE_PARALLELIZATION` environment variable is present. This significantly reduces CI runtime for the comprehensive test suite.

## Fixture Conventions and Access Patterns

Maybe uses Rails' built-in fixture system with YAML files stored in `test/fixtures/*.yml`. The `fixtures :all` declaration in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb) ensures every test case automatically loads the complete fixture dataset, providing predictable baseline data for each test run.

Fixture access follows the standard Rails naming convention. The fixture file name (e.g., [`users.yml`](https://github.com/maybe-finance/maybe/blob/main/users.yml)) determines the helper method name, while the YAML key identifies the specific record:

```ruby

# Accessing fixtures in any test file

users(:family_admin)          # From test/fixtures/users.yml

accounts(:checking)          # From test/fixtures/accounts.yml

transactions(:one)            # From test/fixtures/transactions.yml

```

The database state rolls back automatically after each test due to Rails' transactional fixtures, eliminating the need for manual teardown methods.

## Writing Model Tests with Setup and Assertions

Individual test classes follow a consistent structure: a `setup` method for common data preparation, the `test "description" do ... end` DSL for test cases, and standard Minitest assertions. This pattern appears throughout `test/models/*_test.rb` files.

```ruby

# test/models/user_test.rb

class UserTest < ActiveSupport::TestCase
  def setup
    @user = users(:family_admin)   # Fixture lookup

  end

  test "should be valid" do
    assert @user.valid?, @user.errors.full_messages.to_sentence
  end

  test "email must be present" do
    potential_user = User.new(
      email: "david@davidbowie.com",
      password_digest: BCrypt::Password.create("password"),
      first_name: "David",
      last_name: "Bowie"
    )
    potential_user.email = "     "
    assert_not potential_user.valid?
  end
end

```

The `setup` method runs before each individual test, typically assigning fixture instances to instance variables for reuse across multiple test cases. Assertions use standard Minitest methods including `assert`, `assert_not`, `assert_equal`, `assert_match`, and `assert_raises`.

## Controller and Integration Testing with Helper Methods

Controller tests in `test/controllers/*_test.rb` leverage custom helper methods defined in `ActiveSupport::TestCase` to reduce boilerplate. The `sign_in(user)` method authenticates a fixture user before exercising controller actions.

```ruby

# test/controllers/transactions_controller_test.rb

class TransactionsControllerTest < ActionDispatch::IntegrationTest
  test "creates a transaction when signed in" do
    user = users(:family_admin)
    sign_in(user)                               # Defined in test_helper.rb

    assert_difference "Transaction.count", 1 do
      post transactions_path, params: {
        transaction: { amount: 250, account_id: accounts(:savings).id }
      }
    end

    assert_redirected_to transaction_path(Transaction.last)
  end
end

```

Additional helper methods include `with_env_overrides` for temporary environment variable changes, `with_self_hosting` for testing self-hosted configuration paths, and `user_password_test` for authentication-specific scenarios. These methods keep test files concise while maintaining explicit setup steps.

## Mocking External Services with Mocha and VCR

For external API safety, the test suite combines Mocha for stubbing and mocking with VCR for HTTP interaction recording. Mocha provides `expects` and `stubs` methods for behavior verification, while VCR cassettes in `test/vcr_cassettes/*` prevent real network calls during CI execution.

```ruby

# test/jobs/sync_job_test.rb

class SyncJobTest < ActiveSupport::TestCase
  test "calls SyncAccountsJob for every family" do
    family = families(:primary)

    SyncAccountsJob.any_instance.expects(:perform).once

    SyncJob.perform_now(family.id)
  end
end

```

The `require "mocha/minitest"` line at the top of [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb) enables these mocking capabilities throughout the suite. This approach ensures background job tests run deterministically without executing actual external service calls.

## Summary

- **Base Configuration**: All tests inherit from `ActiveSupport::TestCase` configured in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb) with automatic parallelization and `fixtures :all`.
- **Fixture Access**: Use symbol-based lookup like `users(:family_admin)` to access YAML fixture data from `test/fixtures/*.yml`.
- **Test Structure**: Implement `setup` methods for shared data, use the `test "description"` DSL for individual cases, and rely on standard Minitest assertions.
- **Helper Methods**: Leverage `sign_in`, `with_env_overrides`, and other custom helpers defined in the base test class to DRY common testing scenarios.
- **External APIs**: Combine Mocha stubs with VCR cassettes to isolate tests from network dependencies and ensure deterministic execution.

## Frequently Asked Questions

### How does Maybe configure parallel test execution?

According to the source code in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb), Maybe enables parallel execution via `parallelize(workers: :number_of_processors)` within the `ActiveSupport::TestCase` class definition. This setting automatically detects the host machine's CPU count and distributes tests across multiple processes. Developers can disable this behavior by setting the `DISABLE_PARALLELIZATION` environment variable, which is useful for debugging or running tests in resource-constrained environments.

### What is the difference between `fixtures :all` and loading specific fixtures?

The Maybe codebase uses `fixtures :all` in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb) to automatically load every YAML fixture file found in `test/fixtures/` for every test case. This ensures consistent baseline data availability across the entire suite. While Rails supports specifying individual fixtures (e.g., `fixtures :users, :accounts`), the project opts for the comprehensive approach to simplify fixture management, relying on transactional rollbacks to maintain test isolation rather than selective loading.

### How are external API calls prevented during test runs?

The project uses two complementary strategies implemented in [`test/test_helper.rb`](https://github.com/maybe-finance/maybe/blob/main/test/test_helper.rb). First, VCR records HTTP interactions to `test/vcr_cassettes/*` and replays them during subsequent test runs, eliminating network latency and flakiness. Second, Mocha provides stubbing capabilities via `expects` and `stubs` methods to mock object behavior, ensuring that code paths depending on external services execute without making actual network requests during continuous integration.

### Where should I place new test files in the Maybe repository?

Following the established convention, new tests belong in `test/models/*_test.rb` for unit tests, `test/controllers/*_test.rb` for integration tests, or `test/jobs/*_test.rb` for background job tests. Every test file must end with the [`_test.rb`](https://github.com/maybe-finance/maybe/blob/main/_test.rb) suffix to be recognized by the Rails test runner. The class inside should inherit from `ActiveSupport::TestCase` (or `ActionDispatch::IntegrationTest` for controller tests) to gain access to fixtures, parallelization settings, and custom helper methods.