Files
claude-engineering-plugin/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/testing-patterns.md
Kieran Klaassen 6c5b3e40db [2.9.0] Rename plugin to compound-engineering
BREAKING: Plugin renamed from compounding-engineering to compound-engineering.
Users will need to reinstall with the new name:

  claude /plugin install compound-engineering

Changes:
- Renamed plugin directory and all references
- Updated documentation counts (24 agents, 19 commands)
- Added julik-frontend-races-reviewer to docs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 17:32:16 -08:00

4.7 KiB

Testing Patterns

Minitest Setup

Kane exclusively uses Minitest—never RSpec.

# test/test_helper.rb
require "bundler/setup"
Bundler.require(:default)
require "minitest/autorun"
require "minitest/pride"

# Load the gem
require "gemname"

# Test database setup (if needed)
ActiveRecord::Base.establish_connection(
  adapter: "postgresql",
  database: "gemname_test"
)

# Base test class
class Minitest::Test
  def setup
    # Reset state before each test
  end
end

Test File Structure

# test/model_test.rb
require_relative "test_helper"

class ModelTest < Minitest::Test
  def setup
    User.delete_all
  end

  def test_basic_functionality
    user = User.create!(email: "test@example.org")
    assert_equal "test@example.org", user.email
  end

  def test_with_invalid_input
    error = assert_raises(ArgumentError) do
      User.create!(email: nil)
    end
    assert_match /email/, error.message
  end

  def test_class_method
    result = User.search("test")
    assert_kind_of Array, result
  end
end

Multi-Version Testing

Test against multiple Rails/Ruby versions using gemfiles:

test/
├── test_helper.rb
└── gemfiles/
    ├── activerecord70.gemfile
    ├── activerecord71.gemfile
    └── activerecord72.gemfile
# test/gemfiles/activerecord70.gemfile
source "https://rubygems.org"
gemspec path: "../../"

gem "activerecord", "~> 7.0.0"
gem "sqlite3"
# test/gemfiles/activerecord72.gemfile
source "https://rubygems.org"
gemspec path: "../../"

gem "activerecord", "~> 7.2.0"
gem "sqlite3"

Run with specific gemfile:

BUNDLE_GEMFILE=test/gemfiles/activerecord70.gemfile bundle install
BUNDLE_GEMFILE=test/gemfiles/activerecord70.gemfile bundle exec rake test

Rakefile

# Rakefile
require "bundler/gem_tasks"
require "rake/testtask"

Rake::TestTask.new(:test) do |t|
  t.libs << "test"
  t.pattern = "test/**/*_test.rb"
end

task default: :test

GitHub Actions CI

# .github/workflows/build.yml
name: build

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        include:
          - ruby: "3.2"
            gemfile: activerecord70
          - ruby: "3.3"
            gemfile: activerecord71
          - ruby: "3.3"
            gemfile: activerecord72

    env:
      BUNDLE_GEMFILE: test/gemfiles/${{ matrix.gemfile }}.gemfile

    steps:
      - uses: actions/checkout@v4

      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: ${{ matrix.ruby }}
          bundler-cache: true

      - run: bundle exec rake test

Database-Specific Testing

# .github/workflows/build.yml (with services)
services:
  postgres:
    image: postgres:15
    env:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - 5432:5432
    options: >-
      --health-cmd pg_isready
      --health-interval 10s
      --health-timeout 5s
      --health-retries 5

env:
  DATABASE_URL: postgres://postgres:postgres@localhost/gemname_test

Test Database Setup

# test/test_helper.rb
require "active_record"

# Connect to database
ActiveRecord::Base.establish_connection(
  ENV["DATABASE_URL"] || {
    adapter: "postgresql",
    database: "gemname_test"
  }
)

# Create tables
ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.string :email
    t.text :encrypted_data
    t.timestamps
  end
end

# Define models
class User < ActiveRecord::Base
  gemname_feature :email
end

Assertion Patterns

# Basic assertions
assert result
assert_equal expected, actual
assert_nil value
assert_empty array

# Exception testing
assert_raises(ArgumentError) { bad_code }

error = assert_raises(GemName::Error) do
  risky_operation
end
assert_match /expected message/, error.message

# Refutations
refute condition
refute_equal unexpected, actual
refute_nil value

Test Helpers

# test/test_helper.rb
class Minitest::Test
  def with_options(options)
    original = GemName.options.dup
    GemName.options.merge!(options)
    yield
  ensure
    GemName.options = original
  end

  def assert_queries(expected_count)
    queries = []
    callback = ->(*, payload) { queries << payload[:sql] }
    ActiveSupport::Notifications.subscribe("sql.active_record", callback)
    yield
    assert_equal expected_count, queries.size, "Expected #{expected_count} queries, got #{queries.size}"
  ensure
    ActiveSupport::Notifications.unsubscribe(callback)
  end
end

Skipping Tests

def test_postgresql_specific
  skip "PostgreSQL only" unless postgresql?
  # test code
end

def postgresql?
  ActiveRecord::Base.connection.adapter_name =~ /postg/i
end