Agent skill

Rspec Unit Testing Standards

by ruby-git in ruby-git/ruby-git

Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability.

MITAuto-check passedTesting & QA

Install Rspec Unit Testing Standards

skills CLI
$ npx skills add ruby-git/ruby-git --skill rspec-unit-testing-standards -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ruby-git/ruby-git rspec-unit-testing-standards --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ruby-git/ruby-git.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.github/skills/rspec-unit-testing-standards .claude/skills/rspec-unit-testing-standards && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
rspec-unit-testing-standards
GitHub stars
1.8k
Token cost
~7.8k tokens
SKILL.md length
3,321 words
Files
1
Skills in repo
30
Repo updated
First seen
Licence
MIT

At a glance

Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability.

  • Works in 2 steps: The spec is self-contained documentation… → It guards against an accidental def…
  • Auditing RSpec specs under spec/unit/
  • SKILL.md covers Priority Levels, Contents, How to use this skill and Related skills, plus 5 more sections
  • Calls bundle

What it does

Rspec Unit Testing Standards is an agent skill from ruby-git/ruby-git. Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability. Use when writing, reviewing, or auditing RSpec specs under spec/unit/.

Its SKILL.md is about 7.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Testing & QA, covering Unit testing. The repository describes itself as: Ruby/Git is a Ruby library that can be used to create, read and manipulate Git repositories by wrapping system calls to the git binary. The licence is MIT.

When your agent uses it

  • Auditing RSpec specs under spec/unit/
  • Tasks that involve Unit testing

Example prompts

  • “Use the rspec-unit-testing-standards skill to define RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing…”
  • “/rspec-unit-testing-standards”

Workflow steps

2 steps, taken from the first numbered list in SKILL.md.

  1. The spec is self-contained documentation of the constructor signature — a reader
  2. It guards against an accidental def initialize override in the subclass that

What it can do on your machine

Read from SKILL.md and the folder at commit f3bf20f. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • bundle

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Rspec Unit Testing Standards loads about 7.8k tokens when it runs. Until then it costs about 61 tokens; SKILL.md has 3,321 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~61
When it runs · the whole SKILL.md, loaded when a task matches
~7.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from ruby-git/ruby-git at commit f3bf20f, republished under its MIT licence (© ruby-git). 3,321 words, ~7,798 tokens.

Download SKILL.mdSave it as .claude/skills/rspec-unit-testing-standards/SKILL.md (or your agent's skills folder).
name
rspec-unit-testing-standards
description
Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability. Use when writing, reviewing, or auditing RSpec specs under spec/unit/.

RSpec Unit Testing Standards

These rules govern the structure, organization, and quality of all RSpec unit tests in this project. Apply them when writing new tests, reviewing existing ones, or auditing test quality.

Priority Levels

Use RFC-style priority words to reduce ambiguity for AI behavior:

  • MUST: mandatory; do not violate without a documented exception
  • SHOULD: preferred default; may be overridden when a clearer test requires it

Contents

How to use this skill

These rules apply to all RSpec unit specs under spec/unit/. Extend this baseline with domain-specific rules from related skills as needed.

Adoption and enforcement notes:

  • Apply these rules as hard requirements for new and modified unit specs.
  • Legacy specs may violate some rules; treat those as incremental cleanup work.
  • Branch and line coverage are both reported by SimpleCov in this repository.
  • minimum_coverage: { line: 100, branch: 100 } is configured and enforced: a full rake spec:unit run fails when either threshold is missed, and CI fails the pull request with it. Rule 21 is a build gate, not just a review check. See the Test coverage policy in CONTRIBUTING.md for the full policy.
  • Focused runs (SPEC=<glob> rake spec:unit, or rspec <file>) report coverage but do not fail on it, since they load all of lib/ while exercising only a slice.
  • Testing Guide — the vocabulary these rules are written in and the reasoning behind them; read it when asking why a rule exists
  • Command Test Conventions — additional conventions for Git::Commands::* unit and integration specs, built on top of these rules
  • Development Workflow — TDD process that governs when and how tests are written
  • PR Readiness Review — final quality gate that verifies test compliance before opening a pull request
  • Pull Request Review — PR review process that checks test quality against these standards

Structure

Rule 1 (MUST): One top-level RSpec.describe block per class

Use the class constant directly:

ruby
RSpec.describe Git::CommandLine::Capturing do

Never use a string in place of the constant, even for backward-compat aliases:

ruby
# Bad — string describe; described_class is unavailable, coverage tooling may not
# map the spec to the source file, and typos go undetected at load time.
RSpec.describe 'Git::CommandLine::Result' do

If a class is also reachable through a backward-compat alias constant, the spec that covers the alias uses the alias constant itself as the describe argument — the alias is a real Ruby constant and loads without issue. That spec verifies only that the alias points to the correct target using object identity (be), which a NameError on the canonical constant would not catch. Do not test #initialize or other behavior there — the spec for the canonical class already covers it. The project has no such alias today: Git::CommandLineResult was the last one, and v6.0.0 removed it.

Rule 2 (MUST): One describe block per public method

Use #method_name for instance methods and .method_name for class methods. Include #initialize:

ruby
describe '#call' do ...
describe '.build' do ...
describe '#initialize' do ...

Inherited #initialize in concrete subclasses (SHOULD): If a class is directly instantiated by callers but does not override #initialize, its spec SHOULD still include a describe '#initialize' block using the minimal have_attributes form (see Rule 13). This serves two purposes:

  1. The spec is self-contained documentation of the constructor signature — a reader does not need to consult the ancestor's spec to know what arguments the class accepts or what attributes it exposes.
  2. It guards against an accidental def initialize override in the subclass that silently drops or misroutes an argument, which the ancestor's spec would not catch.

Omit the inherited #initialize block only for abstract or internal classes that callers never instantiate directly — those are sufficiently covered by the ancestor's spec alone.

Rule 3 (SHOULD): Add # frozen_string_literal: true at the top of every spec file

Matches project-wide convention and catches accidental string mutation.

Rule 4 (MUST): Spec file location must mirror source file location

lib/git/foo/bar.rb maps to spec/unit/git/foo/bar_spec.rb. Deviating from this makes specs hard to find and breaks coverage mapping.

Rule 5 (MUST): require 'spec_helper' and only the file(s) under test

Every unit spec MUST start with require 'spec_helper', then require only the Ruby file(s) it directly tests. Avoid requiring unrelated libraries or classes — doing so creates false coupling where a rename or move breaks specs that don't even test that class.

Rule 6 (MUST): Test only through the public interface

Never call private methods directly in tests. If private logic is hard to reach through the public interface, stop and propose one of these remedies to the user:

  • Extract a class — move the logic to a new class with its own public interface.
  • Make the method public — promote it if it is genuinely part of the contract.
  • Redesign the public API — split the public method into smaller public steps.

Never use send, instance_variable_get, or __send__ to reach private state.

Naming and Organization

Rule 7 (SHOULD): Use described_class

Use described_class instead of repeating the class name inside the describe block:

ruby
subject(:result) { described_class.new(args).call }
Rule 8 (MUST): context blocks describe conditions

Use prefixes "when", "with", or "without". Nest them under the relevant describe block for different option combinations, input states, or environmental conditions:

ruby
context 'when the command fails' do ...
context 'with the :force option' do ...
context 'without a timeout' do ...
Rule 9 (MUST): it blocks assert one concept, and the description must match the assertion

Each example tests a single logical behavior. A test described as "raises ArgumentError when options conflict" must verify both the error class and a message pattern — not just that any error was raised. Multiple expect calls are acceptable if they all verify the same behavior — that is, a single application code change would cause them all to fail together. For example, asserting the type, status, and contents of a single return value is one concept ("the result carries the right data"), not five separate behaviors:

ruby
# Good — all assertions verify one concept: the returned result is correct
it 'returns a result with the failure details' do
  result = described_instance.run('status', raise_on_failure: false)
  expect(result).to be_a(Git::CommandLine::Result)
  expect(result.status.success?).to be false
  expect(result.status.exitstatus).to eq(1)
  expect(result.stdout).to eq("modified: foo.rb\n")
  expect(result.stderr).to eq('fatal: not a git repository')
end
Rule 10 (SHOULD): Use the standard nesting pattern
describe #method
  context "when X"
    context "with Y option"
      it "does Z"

Exception: Simple methods with a single execution path and no meaningful input variations do not need context blocks. A describe #method block containing it directly is fine when there are no conditions worth naming.

Setup and Subject

Rule 11 (SHOULD): Use a named subject at the top of each describe #method block

Name the subject after what is returned. For simple cases, inline construction is fine:

ruby
subject(:result) { described_class.new(command, options).call }

When construction is complex or shared across multiple describe blocks, separate construction into a let and reference it from subject (see Rule 14). Naming the subject allows both is_expected.to one-liners and expect(result).to in more descriptive examples. Do not override subject in nested context blocks — vary behavior by overriding let inputs instead.

Rule 12 (SHOULD): Immediately follow subject with let defaults

subject must be the first declaration in a describe block. Do not place let declarations above subject — doing so buries the call under test and inverts the natural reading order (what is being tested → what inputs it receives).

Define let defaults for all inputs and arguments immediately after subject. Nested context blocks override only the let values relevant to that scenario — leave everything else at its default:

ruby
# Good — subject first, then let defaults
describe '#call' do
  subject(:result) { described_class.new(command, options).call }

  let(:command) { ['git', 'status'] }
  let(:options) { {} }

  context 'when options include timeout' do
    let(:options) { { timeout: 10 } }
    it { is_expected.to ... }
  end
end

# Bad — let declarations above subject obscure what is under test
describe '#call' do
  let(:command) { ['git', 'status'] }
  let(:options) { {} }
  subject(:result) { described_class.new(command, options).call }
end
Rule 13 (SHOULD): Define let(:described_instance) at the top level when multiple describe blocks share the same instance

When two or more describe #method blocks instantiate the class identically, define a single let(:described_instance) at the top of the RSpec.describe block instead of repeating construction in every subject. Each describe block then defines subject as the method call result, referencing described_instance:

ruby
RSpec.describe Git::CommandLine do
  let(:command)            { ['git', 'status'] }
  let(:options)            { {} }
  let(:described_instance) { described_class.new(command, options) }

  describe '#call' do
    subject(:result) { described_instance.call }
    ...
  end

  describe '#to_s' do
    subject(:result) { described_instance.to_s }
    ...
  end
end

Guidelines:

  • Use let, not subject — avoids making it the implicit assertion target.

  • Reference only let-defined arguments — no inline literals; nested contexts must be able to override individual inputs.

  • Omit when construction is trivial or varies between methods.

  • For #initialize, alias it: subject(:instance) { described_instance }.

  • When #initialize only stores arguments via attr_reader, use a single have_attributes example — separate it blocks for each attribute add noise without isolation benefit when there is no conditional logic to branch on:

    ruby
    describe '#initialize' do
      subject(:instance) { described_instance }
    
      it 'stores all constructor arguments' do
        expect(instance).to have_attributes(
          env: env,
          binary_path: binary_path,
          global_opts: global_opts,
          logger: logger
        )
      end
    end

    Use separate it blocks only when #initialize performs validation or conditional logic — each branch then deserves its own example.

Rule 14 (SHOULD): Prefer subject to represent the method call result

Prefer subject as the return value of the public method under test. For simple cases, inline construction is fine (see Rule 11). When construction is complex or reused across multiple describe blocks, separate construction into a let so that nested context blocks can override individual inputs without duplicating the whole call:

ruby
# Good — complex construction is separated so inputs can be overridden
let(:instance) { described_class.new(complex, args, here) }
subject(:result) { instance.call }

# Avoid when construction is complex — nested contexts cannot vary individual args
subject(:result) { described_class.new(complex, args, here).call }

Exception: #initialize tests — the constructed object is the return value, so subject should be the instance (see Rule 13 aliasing guideline).

Rule 15 (SHOULD): Do not use subject when testing side effects

Use change and raise_error matchers instead of manual before/after assertions:

ruby
# Good
expect { action }.to change(collection, :size).by(1)
expect { action }.to change(obj, :attr).from('old').to('new')

# Bad
before_count = collection.size
action
expect(collection.size).to eq(before_count + 1)
Rule 16 (MUST): Use let/let! for inputs and shared setup; use before only for side effects

Use let for values that are referenced directly in examples. Use let! when a value must exist before the example runs but is not referenced directly (e.g., a precondition that other code depends on). Use before only for imperative side effects (e.g., creating files, setting env vars). Avoid instance variables set in before blocks.

Rule 17 (SHOULD): Keep test setup local; extract only for substantial cross-file reuse

shared_context is appropriate when identical multi-step environment setup must be shared across multiple spec files and duplicating it inline would be substantial. Do not use shared_context within a single spec file — use the let hierarchy instead. A unit test that needs a shared_context to run is almost certainly an integration test; move it to spec/integration/.

The same restraint applies to shared helper methods. Do not extract a helper to a support file solely because two spec files contain methods with similar structure. If the helpers construct different doubles, mock different classes, or carry different default attributes, the similarity is incidental — not meaningful duplication. Each spec file should be self-contained and readable without jumping to external helpers. Extract only when the helpers are truly identical and used across three or more spec files.

Defining shared contexts:

  • Define in spec/support/contexts/, named after the context string.
  • Use only let, let!, and before/after — no subject, doubles, or described_instance.
  • Reference only let-defined values; never inline literals.

Consuming: always use explicit include_context 'name' — never metadata-based auto-inclusion.

Doubles and Stubbing

Rule 18 (MUST): Stub calls to non-trivial external objects

Stub anything whose real involvement would make the test cross a unit boundary (e.g., ProcessExecuter, file system, network). Do not stub simple value types like String, Integer, or Array. The guiding question: would running the real thing make this test not a unit test?

Exception: Simple value objects with no IO (e.g., Git::CommandLine::Result) can be used directly if doing so keeps the test a unit test.

Show full SKILL.md (1,320 more words)Show less
Rule 19 (MUST): Use allow for incidental stubs; use expect for behavioral assertions

Reserve expect(...).to receive(...) for cases where the call itself is the behavior under test. Use allow for everything else — overusing expect stubs creates over-specified tests that break on irrelevant refactors:

ruby
# Good — incidental stub; test verifies the return value
allow(executer).to receive(:run).and_return(result)
expect(subject).to eq(expected)

# Good — the call itself is what's being verified
expect(executer).to receive(:run).with('git', 'status')
subject

# Good — the call is behavioral and arguments require destructuring;
# use a block with nested expects when .with() cannot cleanly express
# the assertion (e.g., complex kwargs mixed with positional args)
expect(executer).to receive(:run) do |*args, **opts|
  expect(opts[:timeout_after]).to eq(5)
  mock_result
end
subject
Rule 20 (MUST): Use verifying doubles

Use instance_double / class_double rather than plain double:

ruby
# Good — ProcessExecuter.run is a class method; use class_double
let(:process_executer) { class_double(ProcessExecuter) }

# Bad
let(:process_executer) { double('ProcessExecuter') }

Exceptions:

  • Plain double is acceptable when the class being stubbed cannot be loaded in the test environment (e.g., a C extension or optional dependency not available in CI).
  • Plain double is acceptable for duck-type collaborators where there is no single concrete class to verify against (e.g., execution_context in command specs implements a duck-type interface, not one specific class).
  • Plain double is acceptable when the class delegates methods via SimpleDelegator, Delegator, or method_missing. instance_double only verifies methods that method_defined? returns true for, so delegated methods (e.g., signaled?, exitstatus forwarded from Process::Status) would be incorrectly rejected.

In all cases, document the reason with an inline comment so the use of double is not mistaken for carelessness:

ruby
# Duck-type collaborator: command specs depend on the #command_capturing
# interface, not a single concrete ExecutionContext class.
let(:execution_context) { double('ExecutionContext') }

# Plain double: ProcessExecuter result classes delegate to Process::Status
# via SimpleDelegator/method_missing, so instance_double cannot verify the
# delegated interface (signaled?, exitstatus, etc.).
double('ProcessExecuter::ResultWithCapture', success?: true, signaled?: false)

Coverage

Rule 21 (MUST): Achieve 100% branch-level coverage

Every conditional path through the public interface must be exercised by at least one example. If a branch cannot be reached through the public interface, that is a design smell.

This is enforced by the build: a full rake spec:unit run fails below 100% line or branch coverage, and the failure output names each uncovered line and branch.

When a branch is hard to cover, apply these in order:

  1. Reach it through the public interface — if it is reachable, test it.
  2. Delete it — a branch unreachable through the public interface is usually dead code. Removing it is preferable to excluding it.
  3. Exclude it with # simplecov:disable — the last resort, per the exception below.

Exception: Defensive guards that require breaking OS-level invariants to reach (e.g., raise "unreachable" that would require triggering out-of-memory) may be excluded. Mark them explicitly with a # simplecov:disable directive carrying a reason — never leave branches silently uncovered. Cover the smallest possible span, and expect a reviewer to challenge it. lib/ currently contains no coverage directives.

Prefer the inline form for a single line. It applies only to its own line and needs no matching enable, so a region can never be left open by accident:

ruby
raise 'unreachable' # simplecov:disable defensive guard; only reachable on OOM

Use the block form only for a genuine span, and close it explicitly:

ruby
# simplecov:disable branch platform-specific fallback; not reachable on MRI
...
# simplecov:enable branch

Always name the narrowest criterion that solves the problem — line, branch, method, or a comma-separated combination — and write the reason after it, so the required justification lives in the directive.

Review check: verify the criterion is spelled exactly. A word SimpleCov does not recognize is parsed as free-form reason text, which silently widens the directive to all three criteria rather than failing.

Coverage is a floor on evidence, not a proof of correctness. Never write an example whose only purpose is to execute a line. Such a test turns the report green while violating Rule 24, and must be rejected in review.

Rule 22 (MUST): Error assertions must specify both the error class and a message pattern

raise_error(ErrorClass) alone is underspecified — any instance of that class satisfies it regardless of cause. This applies equally when using the block form to verify properties of the raised error object: the block does not substitute for a message check, and RSpec allows both together.

ruby
# Good — class + message pattern only
expect { action }.to raise_error(ArgumentError, /cannot combine :force and :dry_run/)

# Good — class + message pattern + block to verify error properties
expect { action }.to raise_error(Git::FailedError, /git.*status/) do |error|
  expect(error.result.status.exitstatus).to eq(1)
end

# Bad — passes for any ArgumentError, even unrelated ones
expect { action }.to raise_error(ArgumentError)

# Bad — block form is not an exception to the message requirement;
# still passes for any Git::FailedError regardless of cause
expect { action }.to raise_error(Git::FailedError) do |error|
  expect(error.result.status.exitstatus).to eq(1)
end

Version-variance exception: When the error message is produced by an external library or by git itself and is likely to vary across git versions, use the loosest regexp that still distinguishes this error from an unrelated one. Anchor the pattern on something stable — the invalid input value, the subcommand name, or a keyword that appears in all known git versions. Never omit the message check entirely:

ruby
# Good — stable anchor, tolerates phrasing differences across git versions
expect { command.call('nonexistent.txt') }
  .to raise_error(Git::FailedError, /nonexistent\.txt/)

# Good — subcommand keyword is stable across versions
expect { command.call('bad-ref') }
  .to raise_error(Git::FailedError, /bad-ref/)

# Bad — passes for any Git::FailedError regardless of cause
expect { command.call('nonexistent.txt') }.to raise_error(Git::FailedError)
Rule 23 (MUST): Test edge cases within the relevant context block

nil, empty collections, and boundary values belong alongside the normal cases for the same method and condition — not in a separate "edge cases" block at the bottom.

Rule 24 (MUST): Assert observable behavior, not implementation details

Every expect must verify a meaningful outcome — a return value, a raised error, a state change, or a message sent to a collaborator. Do not write assertions that merely confirm the code runs without error or that mirror the implementation:

ruby
# Good — asserts the meaningful return value
expect(subject).to eq('v2.43.0')

# Bad — passes for any non-nil return, verifies nothing useful
expect(subject).not_to be_nil

Decision test — independent failure mode: Before writing or approving an assertion, ask: "What application code change would cause only this test to fail?" If the answer is "nothing — every other test would also fail first," the assertion is redundant and should be removed.

Anti-pattern: structural identity and constant-existence tests

Do not write tests that only verify a constant exists, that a require loaded successfully, or that a namespace is a Module vs a Class:

ruby
# Bad — proves nothing about behavior; any real test that uses the class
# would fail with NameError first if the constant were missing
it 'exposes Capturing' do
  expect(Git::CommandLine::Capturing).to be_a(Class)
end

# Bad — structural choice, not observable behavior from a caller's perspective
it 'is a module (not a class)' do
  expect(described_class).to be_a(Module)
end

Constant presence is proven implicitly by every test that instantiates or calls the class. These tests add no coverage of behavior and should not be written or approved in review.

Test Reliability

Rule 25 (MUST): Keep unit tests deterministic

Do not depend on real time, randomness, sleep-based timing, or external process timing. Stub or freeze Time.now, Process.clock_gettime, SecureRandom, and rand so results are repeatable. Never use sleep in unit tests.

Rule 26 (MUST): Do not modify global/process state

Unit tests must not modify process or global state (for example ENV, the current working directory, locale, or global config) and must not leak state across examples. Inject the value so the test never touches the global; a subject that reads a global directly usually wants a parameter that defaults to it.

Exception: Allowed only when the code under test exists to read that state and has no seam. If used, change the state inside an around hook that restores it even when the example fails, and add an inline comment explaining why. Restoration does not make the mutation safe for other threads in the process, including threads started by an earlier example, so prefer introducing a seam in a follow-up change.

Rule 27 (MUST): Tests must be order-independent

Every unit test must pass when run alone and when run in randomized order. Do not rely on side effects from other examples, files, or execution order.

Rule 28 (MUST): Avoid allow_any_instance_of and receive_message_chain

Do not use allow_any_instance_of or receive_message_chain in unit tests. They hide object boundaries and create brittle tests.

Exception: Allowed only when there is no practical seam and refactoring is out of scope for the current change. If used, add an inline comment explaining why and prefer introducing a seam in a follow-up change.

Verification

After writing or modifying tests, verify compliance before finishing:

  1. Run the specs: bundle exec rspec spec/unit/path/to_spec.rb
  2. Check branch coverage meets 100% (Rule 21) — open coverage/index.html and confirm no uncovered lines or branches in the class under test. A focused run reports coverage but does not fail on it; bundle exec rake spec:unit is the authority and will fail below 100%, naming each uncovered line and branch.
  3. Re-check MUST rules. Scan the spec against every MUST rule. Fix violations.
  4. Run in random order (Rule 27): bundle exec rspec spec/unit/path/to_spec.rb --order rand

Repeat until all checks pass.

Output

When writing new tests, produce the spec file and run through the Verification checklist above. No additional structured output is required.

When reviewing or auditing existing tests, produce the following:

  1. A per-rule compliance table:

    RuleStatusIssue

    Use Pass, Fail, or N/A for each rule.

  2. A summary of required fixes (MUST-level violations).

  3. A list of suggested improvements (SHOULD-level deviations), ordered by impact.

© ruby-git, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .github/skills/rspec-unit-testing-standards of ruby-git/ruby-git.

Open the folder on GitHubat commit f3bf20f

Compare with similar skills

Rspec Unit Testing Standards next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Rspec Unit Testing Standards compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Rspec Unit Testing Standards this skillruby-git/ruby-git1.8k—~7.8kAutomated safety check: PassMIT
TDD WorkflowhellangleZ/burn-in-cceverywhere-ralph11211 repos~2.4kAutomated safety check: PassNone
Testing OpenLogi UIAprilNEA/OpenLogi23k—~1.1kAutomated safety check: PassApache-2.0
Go Testingcxuu/golang-skills1701 repos~1.3kAutomated safety check: PassApache-2.0
Contractssamchon/nestia2.2k—~1.3kAutomated safety check: PassMIT
Cohesion Over TestabilityEpicenterHQ/epicenter4.8k—~2kAutomated safety check: PassCustom licence

Similar skills

  • TDD Workflow

    hellangleZ/burn-in-cceverywhere-ralph

    A skill your agent uses when writing new features, fixing bugs, or refactoring code.

    112 GitHub starsUsed in 11 repos~2.4k tokens
    Testing & QAAuto-check passed
  • Testing OpenLogi UI

    AprilNEA/OpenLogi

    Verifies OpenLogi's native GPUI interface with focused tests, the component gallery and a mock agent, choosing the evidence that fits each change.

    23k GitHub stars~1.1k tokensUpdated 4 days ago
    Testing & QAAuto-check passed
  • Go Testing

    cxuu/golang-skills

    A skill your agent uses when writing, reviewing, or improving Go test code — including table-driven tests, subtests, parallel tests, test helpers, test doubles, and assertions with cmp.Diff.

    170 GitHub starsUsed in 1 repo~1.3k tokens
    Testing & QAAuto-check passed
  • Contracts

    samchon/nestia

    Defines self-acknowledgments for production declarations and tests.

    2.2k GitHub stars~1.3k tokensUpdated today
    Testing & QAAuto-check passed
  • Cohesion Over Testability

    EpicenterHQ/epicenter

    Collapse test-shaped production boundaries while preserving behavior and coverage.

    4.8k GitHub stars~2k tokensUpdated today
    Testing & QAAuto-check passed
  • JS-in-HTML Testing

    liaohch3/claude-tap

    Tests JavaScript embedded in an HTML file in two layers: pytest checks of the logic ported to Python, and Playwright runs in a real browser for the DOM.

    3.3k GitHub stars~924 tokensUpdated 15 days ago
    Testing & QAAuto-check passed

More from ruby-git/ruby-git

All 30 skills in this repo
  • Addresses unresolved pull request review threads and suppressed (low-confidence) Copilot review comments on the current branch, folds each fix into the…

    1.8k GitHub stars~657 tokensUpdated 6 days ago
    Auto-check passed
  • Breaking Change Analysis

    ruby-git/ruby-git

    Assesses what an API change would break before it is made, finds every usage, documents the impact and plans a deprecation or migration path.

    1.8k GitHub stars~1.7k tokensUpdated 6 days ago
    Auto-check passed
  • Diagnoses and fixes failing GitHub Actions runs by identifying the failure, fetching only the relevant logs, finding the root cause and reproducing it locally.

    1.8k GitHub stars~1.9k tokensUpdated 6 days ago
    Auto-check passed
  • Scaffolds and reviews `Git::Commands::*` classes in the ruby-git library, with unit tests, integration tests and YARD docs, using the Base command architecture.

    1.8k GitHub stars~3k tokensUpdated 6 days ago
    Auto-check passed
  • Gem Dependency Management

    ruby-git/ruby-git

    Workflow for updating gem dependencies and fixing CVEs in the ruby-git project: assess with bundle outdated and audit, edit the gemspec, test, then commit with conventional messages.

    1.8k GitHub stars~806 tokensUpdated 6 days ago
    Auto-check passed
  • Migrates a direct command call in Ruby Git's Git::Lib to a Git::Commands class, as part of a Strangler Fig redesign, with a plan, legacy tests and a pull request.

    1.8k GitHub stars~4.4k tokensUpdated 6 days ago
    Auto-check passed

Categories

Questions about Rspec Unit Testing Standards

What does Rspec Unit Testing Standards do?

Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability. Rspec Unit Testing Standards is an agent skill from ruby-git/ruby-git. Defines RSpec unit testing rules for this project covering structure, naming, setup patterns, stubbing, doubles, coverage, and test reliability.

When should I use Rspec Unit Testing Standards?

Rspec Unit Testing Standards fits situations like: auditing RSpec specs under spec/unit/; tasks that involve Unit testing.

How do I install Rspec Unit Testing Standards in Claude Code?

Run `npx skills add ruby-git/ruby-git --skill rspec-unit-testing-standards -a claude-code`. Or copy the skill folder (.github/skills/rspec-unit-testing-standards in ruby-git/ruby-git) into .claude/skills/rspec-unit-testing-standards in your project. Claude Code loads it when a task matches its description.

How do I install Rspec Unit Testing Standards in Codex?

Run `npx skills add ruby-git/ruby-git --skill rspec-unit-testing-standards -a codex`. Or copy the skill folder (.github/skills/rspec-unit-testing-standards in ruby-git/ruby-git) into .agents/skills/rspec-unit-testing-standards in your project. Codex loads it when a task matches its description.

Can I use Rspec Unit Testing Standards in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ruby-git/ruby-git --skill rspec-unit-testing-standards -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/rspec-unit-testing-standards, .gemini/skills/rspec-unit-testing-standards, .github/skills/rspec-unit-testing-standards and .opencode/skills/rspec-unit-testing-standards in your project.

What does Rspec Unit Testing Standards need to run?

Going by SKILL.md and its folder, Rspec Unit Testing Standards needs the command-line tools its instructions call (bundle).

Does Rspec Unit Testing Standards access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Rspec Unit Testing Standards safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Rspec Unit Testing Standards use?

Rspec Unit Testing Standards is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Rspec Unit Testing Standards use?

About 7.8k tokens (SKILL.md is roughly 31k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Rspec Unit Testing Standards?

Skills that share tags, products or a category with Rspec Unit Testing Standards: TDD Workflow (hellangleZ/burn-in-cceverywhere-ralph, 112 stars), Testing OpenLogi UI (AprilNEA/OpenLogi, 23k stars), Go Testing (cxuu/golang-skills, 170 stars) and Contracts (samchon/nestia, 2.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Rspec Unit Testing Standards?

ruby-git (a GitHub organization) maintains it in ruby-git/ruby-git, which has 1,799 GitHub stars. The repository holds 30 skills in this directory. The repository was last updated on October 2, 2026.

Source: ruby-git/ruby-git on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.