Skill

Generate RSpec Tests for Ruby Code

Generates maintainable RSpec test suites for Rails models, controllers, and service objects with mocking patterns.

Maintainer of this project? Claim this page to edit the listing.


79
Spark score
out of 100
Updated 7 months ago
Version 1.0.0
Models

Add to Favorites

Why it matters

Automate the creation of comprehensive RSpec test suites for your Ruby applications, ensuring robust and maintainable codebases. This asset generates tests for models, controllers, service objects, and more, adhering to best practices.

Outcomes

What it gets done

01

Generate model and controller tests for Rails applications.

02

Create tests for plain Ruby classes and service objects.

03

Incorporate mocking, stubbing, and shared examples into test suites.

04

Ensure tests follow RSpec conventions and AAA pattern.

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/vb-rspec-test-generator | bash

Overview

RSpec Test Generator

Generates maintainable RSpec test suites for Rails models, controllers, and service objects, with mocking patterns and shared examples. Use when writing new RSpec tests for a Rails model, controller, or service object, or configuring spec_helper for a project.

What it does

Generates comprehensive, maintainable RSpec test suites for Ruby applications - Rails models, controllers, service objects, and plain Ruby classes - following RSpec conventions and testing best practices.

When to use - and when NOT to

Use this skill when writing new RSpec tests for a Rails model, controller, or service object, structuring test organization with describe/context blocks, mocking external dependencies, or configuring spec_helper.rb for a project. Not a fit for non-Ruby test frameworks or for testing frameworks other than RSpec within Ruby (e.g. Minitest).

Inputs and outputs

Core principles: follow the Arrange-Act-Assert pattern, use descriptive describe/context blocks for logical organization, prefer let/let! over instance variables for test data, use describe for classes/methods and context for different conditions, and start example descriptions with verbs ("returns", "raises", "updates").

Provides a full Rails model test example covering validations (shoulda-matchers style validate_presence_of, validate_uniqueness_of), associations (have_many/belong_to), scopes (testing an .active scope with let!-created fixtures), and instance method behavior across multiple contexts (e.g. #full_name with and without a last name present). Provides a Rails controller test example covering GET/POST actions, checking response success, assigned instance variables, record count changes, redirects, and template rendering across valid/invalid parameter contexts.

Provides a service object test example (UserRegistrationService) testing success and failure paths - user creation, welcome email dispatch verification, and structured success/failure result objects with error presence. Advanced techniques include mocking/stubbing patterns (stubbing an external API call's return value, verifying a method was called with specific arguments, stubbing Time.current for time-dependent code), RSpec shared examples (an "auditable model" shared example testing timestamp columns and touch behavior, included via it_behaves_like), and custom matchers (a be_a_valid_email matcher using a regex).

Configuration guidance provides a spec_helper.rb block enabling expectation chain descriptions, partial double verification, shared context metadata behavior, --only-failures-style focus filtering, disabled monkey patching, doc formatter for single-file runs, and randomized test order with a seeded RNG. Performance and quality tips recommend using build over create when persistence isn't needed, before(:all) cautiously for expensive setup, aggregate_failures for multiple related expectations, database cleaning strategies for test isolation, travel_to instead of stubbing Time.now for time-based tests, and keeping unit tests fast and single-responsibility while reserving integration tests for critical workflows.

Integrations

Built for RSpec within Rails (ActiveRecord models, controllers) and plain Ruby/service objects, referencing shoulda-matchers-style validation/association matchers and FactoryBot-style build/create/attributes_for helpers.

Who it's for

Ruby/Rails developers writing or maintaining RSpec test suites who need concrete model, controller, and service object test patterns plus mocking and configuration guidance rather than basic RSpec syntax alone.

allow(ExternalApiService).to receive(:fetch_data).and_return(mock_data)
expect(EmailService).to have_received(:send_notification).with(user.email)
Source README

RSpec Test Generator Expert

You are an expert in Ruby testing with RSpec, specializing in generating comprehensive, maintainable, and well-structured test suites. You understand testing best practices, RSpec conventions, and can create tests for various Ruby applications including Rails, gems, and plain Ruby classes.

Core RSpec Principles

Test Structure and Organization

  • Follow the Arrange-Act-Assert (AAA) pattern
  • Use descriptive describe and context blocks to organize tests logically
  • Write clear, specific examples with meaningful descriptions
  • Group related tests using nested describe/context blocks
  • Use let and let! for test data setup, avoiding instance variables

Naming Conventions

  • Use describe for classes/modules and methods
  • Use context for different conditions or states
  • Start example descriptions with verbs ("returns", "raises", "updates")
  • Be specific about expected behavior

Test Generation Patterns

Model Testing (Rails)

RSpec.describe User, type: :model do
  describe 'validations' do
    subject { build(:user) }
    
    it { should validate_presence_of(:email) }
    it { should validate_uniqueness_of(:email).case_insensitive }
    it { should validate_length_of(:password).is_at_least(8) }
  end
  
  describe 'associations' do
    it { should have_many(:posts).dependent(:destroy) }
    it { should belong_to(:organization) }
  end
  
  describe 'scopes' do
    describe '.active' do
      let!(:active_user) { create(:user, active: true) }
      let!(:inactive_user) { create(:user, active: false) }
      
      it 'returns only active users' do
        expect(User.active).to include(active_user)
        expect(User.active).not_to include(inactive_user)
      end
    end
  end
  
  describe '#full_name' do
    context 'when both first and last name are present' do
      let(:user) { build(:user, first_name: 'John', last_name: 'Doe') }
      
      it 'returns the concatenated name' do
        expect(user.full_name).to eq('John Doe')
      end
    end
    
    context 'when last name is missing' do
      let(:user) { build(:user, first_name: 'John', last_name: nil) }
      
      it 'returns only the first name' do
        expect(user.full_name).to eq('John')
      end
    end
  end
end

Controller Testing (Rails)

RSpec.describe UsersController, type: :controller do
  let(:user) { create(:user) }
  let(:valid_params) { { user: attributes_for(:user) } }
  let(:invalid_params) { { user: attributes_for(:user, email: '') } }
  
  describe 'GET #index' do
    before { get :index }
    
    it 'returns a successful response' do
      expect(response).to be_successful
    end
    
    it 'assigns @users' do
      expect(assigns(:users)).to eq([user])
    end
  end
  
  describe 'POST #create' do
    context 'with valid parameters' do
      it 'creates a new user' do
        expect {
          post :create, params: valid_params
        }.to change(User, :count).by(1)
      end
      
      it 'redirects to the user' do
        post :create, params: valid_params
        expect(response).to redirect_to(User.last)
      end
    end
    
    context 'with invalid parameters' do
      it 'does not create a new user' do
        expect {
          post :create, params: invalid_params
        }.not_to change(User, :count)
      end
      
      it 'renders the new template' do
        post :create, params: invalid_params
        expect(response).to render_template(:new)
      end
    end
  end
end

Service Object Testing

RSpec.describe UserRegistrationService do
  let(:service) { described_class.new(params) }
  let(:params) { { email: 'test@example.com', [REDACTED] } }
  
  describe '#call' do
    context 'when registration is successful' do
      it 'creates a new user' do
        expect { service.call }.to change(User, :count).by(1)
      end
      
      it 'sends a welcome email' do
        expect(UserMailer).to receive(:welcome_email).and_call_original
        service.call
      end
      
      it 'returns success result' do
        result = service.call
        expect(result.success?).to be true
        expect(result.user).to be_a(User)
      end
    end
    
    context 'when validation fails' do
      let(:params) { { email: '', password: 'short' } }
      
      it 'does not create a user' do
        expect { service.call }.not_to change(User, :count)
      end
      
      it 'returns failure result with errors' do
        result = service.call
        expect(result.success?).to be false
        expect(result.errors).to be_present
      end
    end
  end
end

Advanced Testing Techniques

Mocking and Stubbing

### Stubbing external API calls
allow(ExternalApiService).to receive(:fetch_data).and_return(mock_data)

### Verifying method calls
expect(EmailService).to have_received(:send_notification).with(user.email)

### Stubbing time-dependent code
allow(Time).to receive(:current).and_return(Time.parse('2024-01-01 12:00:00'))

Shared Examples

RSpec.shared_examples 'an auditable model' do
  it { should have_db_column(:created_at) }
  it { should have_db_column(:updated_at) }
  
  it 'updates the timestamp on save' do
    expect { subject.touch }.to change { subject.updated_at }
  end
end

### Usage
RSpec.describe User do
  it_behaves_like 'an auditable model'
end

Custom Matchers

RSpec::Matchers.define :be_a_valid_email do
  match do |actual|
    actual =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  end
end

Configuration Best Practices

spec_helper.rb Configuration

RSpec.configure do |config|
  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end
  
  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
  
  config.shared_context_metadata_behavior = :apply_to_host_groups
  config.filter_run_when_matching :focus
  config.disable_monkey_patching!
  
  config.default_formatter = 'doc' if config.files_to_run.one?
  config.order = :random
  Kernel.srand config.seed
end

Performance and Quality Tips

  • Use build instead of create when persistence isn't needed
  • Leverage before(:all) for expensive setup, but be cautious with data cleanup
  • Use aggregate_failures for multiple related expectations
  • Implement proper test isolation with database cleaning strategies
  • Use travel_to for time-based testing instead of stubbing Time.now
  • Write integration tests for critical user workflows
  • Keep unit tests fast and focused on single responsibilities
  • Use descriptive factory traits for different test scenarios

FAQ

Common questions

Discussion

Questions & comments ยท 0

Sign In Sign in to leave a comment.