askill
rspec-coder

rspec-coderSafety 90Repository

This skill guides writing comprehensive RSpec tests for Ruby and Rails applications. Use when creating spec files, writing test cases, or testing new features. Covers RSpec syntax, describe/context organization, subject/let patterns, fixtures, mocking with allow/expect, and shoulda matchers.

0 stars
1.2k downloads
Updated 2/5/2026

Package Files

Loading files...
SKILL.md

RSpec Coder

Core Philosophy

  • AAA Pattern: Arrange-Act-Assert structure for clarity
  • Behavior over Implementation: Test what code does, not how
  • Isolation: Tests should be independent
  • Descriptive Names: Blocks should clearly explain behavior
  • Coverage: Test happy paths AND edge cases
  • Fast Tests: Minimize database operations
  • Fixtures: Use fixtures for common data setup
  • Shoulda Matchers: Use for validations and associations

Critical Conventions

❌ Don't Add require 'rails_helper'

RSpec imports via .rspec config. Adding manually is redundant.

# ✅ GOOD - no require needed
RSpec.describe User do
  # ...
end

❌ Don't Add Redundant Spec Type

RSpec infers type from file location automatically.

# ✅ GOOD - type inferred from spec/models/ location
RSpec.describe User do
  # ...
end

✅ Use Namespace WITHOUT Leading ::

# ✅ GOOD - no leading double colons
RSpec.describe DynamicsGp::ERPSynchronizer do
  # ...
end

Test Organization

File Structure

spec/
├── models/           # Model unit tests
├── services/         # Service object tests
├── controllers/      # Controller tests
├── requests/         # Request specs (API testing)
├── mailers/          # Mailer tests
├── jobs/             # Background job tests
├── fixtures/         # Test data
├── support/          # Helper modules and shared examples
└── rails_helper.rb   # Rails-specific configuration

Using describe and context

BlockPurposeExample
describeGroups by method/classdescribe "#process"
contextGroups by conditioncontext "when user is admin"
RSpec.describe OrderProcessor do
  describe "#process" do
    context "with valid payment" do
      # success tests
    end

    context "with invalid payment" do
      # failure tests
    end
  end
end

Subject and Let

See resources/patterns.md for detailed examples.

PatternUse Case
subject(:name) { ... }Primary object/method under test
let(:name) { ... }Lazy-evaluated, memoized data
let!(:name) { ... }Eager evaluation (before each test)
RSpec.describe User do
  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { users(:alice) }

    it { is_expected.to eq("Alice Smith") }
  end
end

Fixtures

See resources/patterns.md for detailed examples.

# spec/fixtures/users.yml
alice:
  name: Alice Smith
  email: alice@example.com
  admin: false
RSpec.describe User do
  fixtures :users

  it "validates email" do
    expect(users(:alice)).to be_valid
  end
end

Mocking and Stubbing

See resources/patterns.md for detailed examples.

MethodPurpose
allow(obj).to receive(:method)Stub return value
expect(obj).to receive(:method)Verify call happens
# Stubbing external service
allow(PaymentGateway).to receive(:charge).and_return(true)

# Verifying method called
expect(UserMailer).to receive(:welcome_email).with(user)

Matchers Quick Reference

See resources/matchers.md for complete reference.

Essential Matchers

# Equality
expect(value).to eq(expected)

# Truthiness
expect(obj).to be_valid
expect(obj).to be_truthy

# Change
expect { action }.to change { obj.status }.to("completed")
expect { action }.to change(Model, :count).by(1)

# Errors
expect { action }.to raise_error(SomeError)

# Collections
expect(array).to include(item)
expect(array).to be_empty

Shoulda Matchers

# Validations
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:email) }

# Associations
it { is_expected.to have_many(:posts) }
it { is_expected.to belong_to(:account) }

AAA Pattern

Structure all tests as Arrange-Act-Assert:

describe "#process_refund" do
  subject(:process_refund) { processor.process_refund }

  let(:order) { orders(:completed_order) }
  let(:processor) { described_class.new(order) }

  it "updates order status" do
    process_refund  # Act
    expect(order.reload.status).to eq("refunded")  # Assert
  end

  it "credits user account" do
    expect { process_refund }  # Act
      .to change { order.user.reload.account_balance }  # Assert
      .by(order.total)
  end
end

Test Coverage Standards

What to Test

TypeTest For
ModelsValidations, associations, scopes, callbacks, methods
ServicesHappy path, sad path, edge cases, external integrations
ControllersStatus codes, response formats, auth, redirects
JobsExecution, retry logic, error handling, idempotency

Coverage Example

RSpec.describe User do
  fixtures :users

  describe "validations" do
    subject(:user) { users(:valid_user) }

    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to validate_presence_of(:email) }
    it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
  end

  describe "associations" do
    it { is_expected.to have_many(:posts).dependent(:destroy) }
  end

  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { User.new(first_name: "Alice", last_name: "Smith") }

    it { is_expected.to eq("Alice Smith") }

    context "when last name is missing" do
      let(:user) { User.new(first_name: "Alice") }
      it { is_expected.to eq("Alice") }
    end
  end
end

Anti-Patterns

See resources/anti-patterns.md for detailed examples.

Anti-PatternWhy Bad
require 'rails_helper'Redundant, loaded via .rspec
type: :modelRedundant, inferred from location
Leading :: in namespaceViolates RuboCop style
Empty test bodiesFalse confidence
Testing private methodsCouples to implementation
Not using fixturesSlow tests
Not using shouldaVerbose validation tests

Best Practices Checklist

Critical Conventions:

  • NOT adding require 'rails_helper'
  • NOT adding redundant spec type
  • Using namespace WITHOUT leading ::

Test Organization:

  • describe for methods/classes
  • context for conditions
  • Max 3 levels nesting

Test Data:

  • Using fixtures (not factories)
  • Using let for lazy data
  • Using subject for method under test

Assertions:

  • Shoulda matchers for validations
  • Shoulda matchers for associations
  • change matcher for state changes

Coverage:

  • Happy path tested
  • Sad path tested
  • Edge cases covered

Quick Reference

# Minimal spec file
RSpec.describe User do
  fixtures :users

  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { users(:alice) }

    it { is_expected.to eq("Alice Smith") }
  end

  describe "validations" do
    subject(:user) { users(:alice) }

    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to have_many(:posts) }
  end
end

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

95/100Analyzed 2/10/2026

An excellent, comprehensive guide for RSpec testing in Rails. It provides clear conventions, code examples, and a checklist for best practices that are highly actionable.

90
100
90
95
95

Metadata

Licenseunknown
Version-
Updated2/5/2026
Publishermajiayu000

Tags

apidatabasesecuritytesting