本文へ移動
cccskills
無料GitHub で公開

tdd

Red-green-refactor-lint workflow for RIPDPI plus test-double, FaultQueue, and golden-bless conventions. Use when building a feature or fixing a bug test-first. Not for Kotlin test syntax (use kotlin-test-patterns).

インストール方法を見る

含まれるファイル(2)

  • SKILL.md5.8 KB
  • references/testing-anti-patterns.md5.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Test-Driven Development

Full test stack documentation: docs/testing.md. Do not duplicate it here -- read it when you need runner details, CI lanes, or fixture locations.

Workflow

Repeat this cycle for every behavior change. Write the failing test before any implementation -- do not skip RED.

  1. RED -- Write exactly one failing test. Run it. Confirm it fails for the expected reason.
  2. GREEN -- Write the minimum implementation to make the test pass. Run the test again.
  3. REFACTOR -- Clean up test and implementation. Run tests to confirm nothing broke.
  4. LINT -- Run ./gradlew staticAnalysis before considering the cycle complete.

Never batch multiple behaviors into one cycle. One test, one behavior, one cycle.

Running Tests

Kotlin/JVM (fast iteration)

# Single test method
./gradlew :core:engine:testDebugUnitTest --tests "ClassName.method name"

# Single test class
./gradlew :core:engine:testDebugUnitTest --tests "ClassName"

# Single module
./gradlew :core:engine:testDebugUnitTest

Replace :core:engine with the target module (:core:service, :core:data, :core:diagnostics).

Rust

# Single test
cargo nextest run --locked -p crate_name test_name

# Single crate
cargo nextest run --locked -p crate_name

# Full workspace
cargo nextest run --locked --workspace

Golden contracts

Golden tests are read-only by default. If your change intentionally alters a contract:

# Bless all golden fixtures
bash scripts/tests/bless-telemetry-goldens.sh

# Manual single-suite bless
RIPDPI_BLESS_GOLDENS=1 ./gradlew :core:engine:testDebugUnitTest
RIPDPI_BLESS_GOLDENS=1 cargo test --locked -p crate_name

Always review blessed diffs before committing. Golden changes require explanation in the commit message.

Test Double Conventions

Fake* classes (no mocking frameworks)

All test doubles are hand-written Fakes in core/engine/src/test/kotlin/com/poyka/ripdpi/core/TestDoubles.kt. The project does not use MockK, Mockito, or any mocking library.

Pattern:

  • Name: Fake + interface name (e.g., FakeRipDpiProxyRuntime)
  • Track call counts and last arguments as public properties
  • Return configurable values set before the test runs

FaultQueue for fault injection

Fault injection uses FaultQueue<T> from core/engine-api/src/main/kotlin/com/poyka/ripdpi/core/testing/FaultModel.kt.

Key types:

  • FaultQueue<T> -- ordered queue of faults matched by target enum
  • FaultSpec<T> -- target + outcome + scope + optional message/payload
  • FaultScope.ONE_SHOT -- fires once then is consumed
  • FaultScope.PERSISTENT -- fires on every matching call until cleared
  • FaultOutcome -- EXCEPTION, TIMEOUT, DROP, RESET, MALFORMED_PAYLOAD, BLANK_PAYLOAD, PANIC

Usage in tests:

val bindings = FakeRipDpiProxyBindings()
bindings.faults.enqueue(
    FaultSpec(
        target = ProxyBindingFaultTarget.START,
        outcome = FaultOutcome.EXCEPTION,
        message = "simulated native crash",
    )
)

Test Organization by Layer

What you testLocationRunner
Kotlin business logiccore/*/src/test/./gradlew :core:*:testDebugUnitTest
Rust native logicnative/rust/crates/*/tests/cargo nextest run --locked -p crate
JNI integrationapp/src/androidTest/.../integration/connectedGithubFullDebugAndroidTest
Network E2Eapp/src/androidTest/.../e2e/connectedGithubFullDebugAndroidTest
Rust network E2Enative/rust/crates/*/tests/bash scripts/ci/run-rust-network-e2e.sh

Subagent Strategy

For non-trivial features, use context isolation:

  1. Subagent writes the test -- Launch Claude Code's built-in Explore or general-purpose subagent to write the failing test. This keeps test design independent of implementation bias.
  2. Main context implements -- Read the test the subagent wrote, then implement the minimum code to pass it.
  3. Main context refactors -- Clean up both test and implementation in the same context.

This prevents the "write test and implementation together" anti-pattern.

Rules

  1. Fake doubles only.* No mocking frameworks. Add new Fakes to TestDoubles.kt.
  2. FaultQueue for error paths. Use FaultSpec + FaultQueue, not ad-hoc exception throwing.
  3. Golden contracts are read-only by default. Bless intentionally, review the diff, explain in the commit message.
  4. Use backtick names in Kotlin tests. @Test fun proxy start propagates native exception().
  5. Use snake_case names in Rust tests. fn proxy_start_propagates_native_exception().
  6. Test and implementation land in one commit. Never commit a test without its implementation or vice versa.
  7. Prefer unit tests. Escalate to integration or E2E only when the behavior needs real Android or network components.

Common Mistakes

MistakeFix
Using MockK or MockitoWrite a Fake* class in TestDoubles.kt
Skipping the RED stepRun the test first. If it passes, your test is wrong.
Multiple assertions per cycleSplit into separate test methods, one behavior each
runBlocking in coroutine testsUse runTest from kotlinx-coroutines-test
Blessing goldens without reviewRun git diff on fixture files before committing
Testing private internalsTest through the public API of the class under test
Putting helpers in test classesAdd shared helpers to TestDoubles.kt
FaultScope.PERSISTENT when ONE_SHOT sufficesDefault to ONE_SHOT; use PERSISTENT only for repeated-call scenarios

For deeper coverage of anti-patterns, see references/testing-anti-patterns.md.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

RIPDPI's own Compose conventions: ViewModel pattern, Route/Screen split, DataStore->StateFlow, RipDpiThemeTokens. Use for how this app does Compose, not generic Compose API questions (see compose).

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

ADB-based RIPDPI device/emulator debugging: build/install/launch, logcat filtering, fixture port-forwarding, instrumented tests, crash/ANR triage. Use when debugging on a real device or emulator.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

RIPDPI Appium launch-contract reference: start routes and permission/service/data presets. Use when a test launches to the wrong screen or a new automation route is added. General flakiness: appium-test-debug.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

RIPDPI Appium test authoring: page objects, resource-id locators, assertions, wait tiers. Use when writing a new Appium test or page object, or adding coverage for a new screen.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

RIPDPI Appium failure triage: flaky tests, locator/session/wait issues, screenshot and element-tree debugging. Use when an Appium test fails or is flaky.

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

Add or modify a GitHub Actions job. Use when editing a file under .github/workflows/. Not for running a workflow locally (local-ci-act) or release signing (release-signing).

日本語の概要は準備中です。原文の説明を表示しています。

po4yka/RIPDPI792026年10月11日 更新

po4yka のスキルをすべて見る

このスキルの問題を報告する