Skip to main content
Automated testing is a crucial part of the development process. It helps you ensure that your code works as expected and catches bugs early. Spree uses RSpec, Factory Bot, and Capybara for testing. We also provide the spree_dev_tools gem that helps you write Spree-specific tests.
This guide assumes you’ve completed all previous tutorials through API. You should have a complete Spree::Brand model with admin features and API endpoints.

Setup

If your app came from create-spree-app or spree-starter, the test environment is already set up — RSpec, Factory Bot, Capybara, DatabaseCleaner, and the spree_dev_tools helpers (stub_authorization!, the 'API v3 Store' shared context, Spree factories) ship preconfigured in spec/support/. Skip to creating the fixtures file below.
For an existing Rails app without test setup, install RSpec and the Spree test helpers:
The spree_dev_tools generator adds the Spree-specific helpers to spec/support/: authorization helpers (stub_authorization!), Factory Bot configuration, Capybara setup for feature tests, and more.

Create the Fixtures Directory and File

When writing tests that involve file attachments (like images, PDFs, etc.), you need fixture files that your factories can use. Here’s how to set them up.

What the generators already created

If you used spree generate api_resource in the API step, you already have controller specs (spec/controllers/spree/api/v3/store/brands_controller_spec.rb and …/admin/brands_controller_spec.rb) and a factory (spec/factories/spree/brand_factory.rb). The sections below build the same things by hand — compare as you go, and keep whichever you prefer. For the model spec, create spec/models/spree/brand_spec.rb — we’ll fill it in below.

Writing Factories

Factories provide a convenient way to create test data. Create a factory for your Brand model:
spec/factories/spree/brand_factory.rb

Factory Usage Examples

Writing Model Tests

Model tests verify your business logic, validations, associations, and scopes.
spec/models/spree/brand_spec.rb

Testing Decorators

When you extend core Spree models with decorators (see Extending Core Models), test the added functionality:
spec/models/spree/product_decorator_spec.rb

Writing Controller Tests

Controller tests verify that your endpoints respond correctly and perform the expected actions.

Store API Controller Tests

Test the API endpoints we created in the API tutorial. Store API tests use the 'API v3 Store' shared context which sets up a store, publishable API key, and JWT tokens — it ships in the spree_api gem, so require spree/api/testing_support/v3/base at the top of the spec.
spec/controllers/spree/api/v3/store/brands_controller_spec.rb

Testing the Product Brand Association

Test that the custom Product serializer includes brand data:
spec/controllers/spree/api/v3/store/products_brand_spec.rb

Admin Controller Tests

spec/controllers/spree/admin/brands_controller_spec.rb

Writing Feature Tests

Feature tests (also called system tests) simulate real user interactions using Capybara.

Admin Feature Tests

spec/features/spree/admin/brands_spec.rb

Test Helpers

Authorization Helper

Use stub_authorization! to bypass authorization checks in admin tests:

wait_for_turbo Helper

When testing with Turbo/Hotwire, use wait_for_turbo to ensure the page has fully loaded:

Running Tests

Prepare the test database

Tests run against a dedicated spree_test database, so your development data is never touched. Create it and load the schema once:
You rarely need to run this again — rails_helper.rb re-syncs the test schema automatically when you add migrations. It’s the command to reach for when the test database gets into a broken or out-of-sync state.

Run the suite

spree rspec runs bundle exec rspec inside the web container with RAILS_ENV=test. Everything after rspec is passed through, so file paths, line numbers, and flags work as usual:
Projects scaffolded before July 2026 set DATABASE_URL in docker-compose.dev.yml. A URL overrides config/database.yml for every Rails environment, so in-container tests pointed at the development database and tripped DatabaseCleaner’s remote-URL safeguard. Two small changes bring an older project up to date:
  1. In docker-compose.dev.yml, replace the DATABASE_URL entry under environment: with host/username parts, so each Rails environment resolves its own database from database.yml:
  1. In spec/rails_helper.rb, force the test environment — the dev container bakes in RAILS_ENV=development:
Then restart the stack (Ctrl+C and spree dev) so the container picks up the new environment.

Best Practices

Use build over create

Use build instead of create when you don’t need a persisted record. It’s faster because it skips database operations.

Use let over instance variables

Prefer let and let! over instance variables. They’re lazily evaluated and scoped to each example.

One assertion per test

Keep tests focused on a single behavior. Use aggregate_failures if you need multiple assertions.

Test behavior, not implementation

Focus on what the code does, not how it does it. This makes tests more resilient to refactoring.

Example: aggregate_failures

Complete Test Suite Structure

After completing this tutorial, your test structure should look like: