CtrlK
BlogDocsLog inGet started
Tessl Logo

tdd-cycle

Guides Test-Driven Development workflow with Red-Green-Refactor cycle. Use when the user wants to implement a feature using TDD, write tests first, follow test-driven practices, or mentions red-green-refactor.

Install with Tessl CLI

npx tessl i github:fernandezbaptiste/rails_ai_agents --skill tdd-cycle
What are skills?

86

Does it follow best practices?

Validation for skill structure

SKILL.md
Review
Evals

TDD Cycle Skill

Overview

This skill guides you through the Test-Driven Development cycle:

  1. RED: Write a failing test that describes desired behavior
  2. GREEN: Write minimal code to pass the test
  3. REFACTOR: Improve code while keeping tests green

Workflow Checklist

Copy and track progress:

TDD Progress:
- [ ] Step 1: Understand the requirement
- [ ] Step 2: Choose test type (unit/request/system)
- [ ] Step 3: Write failing spec (RED)
- [ ] Step 4: Verify spec fails correctly
- [ ] Step 5: Implement minimal code (GREEN)
- [ ] Step 6: Verify spec passes
- [ ] Step 7: Refactor if needed
- [ ] Step 8: Verify specs still pass

Step 1: Requirement Analysis

Before writing any code, understand:

  • What is the expected input?
  • What is the expected output/behavior?
  • What are the edge cases?
  • What errors should be handled?

Ask clarifying questions if requirements are ambiguous.

Step 2: Choose Test Type

Test TypeUse ForLocationExample
Model specValidations, scopes, instance methodsspec/models/Testing User#full_name
Request specAPI endpoints, HTTP responsesspec/requests/Testing POST /api/users
System specFull user flows with JavaScriptspec/system/Testing login flow
Service specBusiness logic, complex operationsspec/services/Testing CreateOrderService
Job specBackground job behaviorspec/jobs/Testing SendEmailJob

Step 3: Write Failing Spec (RED)

Spec Structure

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe ClassName, type: :spec_type do
  describe '#method_name' do
    subject { described_class.new(args) }

    context 'when condition is met' do
      let(:dependency) { create(:factory) }

      it 'behaves as expected' do
        expect(subject.method_name).to eq(expected_value)
      end
    end

    context 'when edge case' do
      it 'handles gracefully' do
        expect { subject.method_name }.to raise_error(SpecificError)
      end
    end
  end
end

Good Spec Characteristics

  • One behavior per example: Each it block tests one thing
  • Clear description: Reads like a sentence when combined with describe/context
  • Minimal setup: Only create data needed for the specific test
  • Fast execution: Avoid unnecessary database hits, use build over create when possible
  • Independent: Tests don't depend on order or shared state

Templates

  • See unit_spec.erb for model/service specs
  • See request_spec.erb for API specs

Step 4: Verify Failure

Run the spec:

bundle exec rspec path/to/spec.rb --format documentation

The spec MUST fail with a clear message indicating:

  • What was expected
  • What was received (or that the method/class doesn't exist)
  • Why it failed

Important: If the spec passes immediately, you're not doing TDD. Either:

  • The behavior already exists (check if this is intentional)
  • The spec is wrong (not testing what you think)

Step 5: Implement (GREEN)

Write the MINIMUM code to pass:

  • No optimization yet
  • No edge case handling (unless that's what you're testing)
  • No refactoring
  • Just make it work
# Start with the simplest thing that could work
def full_name
  "#{first_name} #{last_name}"
end

Step 6: Verify Pass

Run the spec again:

bundle exec rspec path/to/spec.rb --format documentation

It MUST pass. If it fails:

  1. Read the error carefully
  2. Fix the implementation (not the spec, unless the spec was wrong)
  3. Run again

Step 7: Refactor

Now improve the code while keeping tests green:

Refactoring Targets

  • Extract methods: Long methods → smaller focused methods
  • Improve naming: Unclear names → intention-revealing names
  • Remove duplication: Repeated code → shared abstractions
  • Simplify logic: Complex conditionals → cleaner patterns

Refactoring Rules

  1. Make ONE change at a time
  2. Run specs after EACH change
  3. If specs fail, undo and try different approach
  4. Stop when code is clean (don't over-engineer)

Step 8: Final Verification

Run all related specs:

bundle exec rspec spec/models/user_spec.rb

All specs must pass. If any fail:

  • Undo recent changes
  • Try a different refactoring approach
  • Consider if the failing spec reveals a real bug

Common Patterns

Testing Validations

describe 'validations' do
  it { is_expected.to validate_presence_of(:email) }
  it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
  it { is_expected.to validate_length_of(:name).is_at_most(100) }
end

Testing Associations

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

Testing Scopes

describe '.active' do
  let!(:active_user) { create(:user, status: :active) }
  let!(:inactive_user) { create(:user, status: :inactive) }

  it 'returns only active users' do
    expect(User.active).to contain_exactly(active_user)
  end
end

Testing Service Objects

describe '#call' do
  subject(:result) { described_class.new.call(params) }

  context 'with valid params' do
    let(:params) { { email: 'test@example.com' } }

    it 'returns success' do
      expect(result).to be_success
    end

    it 'creates a user' do
      expect { result }.to change(User, :count).by(1)
    end
  end

  context 'with invalid params' do
    let(:params) { { email: '' } }

    it 'returns failure' do
      expect(result).to be_failure
    end
  end
end

Anti-Patterns to Avoid

  1. Testing implementation, not behavior: Test what it does, not how
  2. Too many assertions: Split into separate examples
  3. Brittle tests: Don't test exact error messages or timestamps
  4. Slow tests: Use build over create, mock external services
  5. Mystery guests: Make test data explicit, not hidden in factories
Repository
fernandezbaptiste/rails_ai_agents
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.