一键导入
marsai-dev-unit-testing
Gate 3 of development cycle - ensures unit test coverage meets threshold (85%+) for all acceptance criteria using TDD methodology.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Gate 3 of development cycle - ensures unit test coverage meets threshold (85%+) for all acceptance criteria using TDD methodology.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Main orchestrator for the 8-gate development cycle system. Loads tasks/subtasks from PM team output and executes through implementation → devops → SRE → unit testing → integration testing (write) → chaos testing (write) → review → validation gates (Gates 0-7), with state persistence and metrics collection. Gates 4-5 (integration/chaos) write and update test code per unit but only execute tests at end of cycle (deferred execution). Multi-tenant dual-mode is implemented during Gate 0 and verified at Gate 0.5G (no separate post-cycle step).
Gate 5 of development cycle - ensures chaos tests exist using Toxiproxy to verify graceful degradation under connection loss, latency, and partitions.
Gate 1 of the development cycle. Creates/updates Docker configuration, docker-compose setup, and environment variables for local development and deployment readiness.
Gate 4 of development cycle - ensures integration tests pass for all external dependency interactions using real containers via testcontainers.
Gate 4 of development cycle - dispatches 7 specialized reviewers (code, business-logic, security, test, nil-safety, consequences, dead-code) in parallel for comprehensive code review feedback.
Gate 2 of the development cycle. VALIDATES that observability was correctly implemented by developers. Does not implement observability code - only validates it.
| name | marsai:dev-unit-testing |
| description | Gate 3 of development cycle - ensures unit test coverage meets threshold (85%+) for all acceptance criteria using TDD methodology. |
| trigger | - After implementation and SRE complete (Gate 0/1/2) - Task has acceptance criteria requiring test coverage - Need to verify implementation meets requirements |
| skip_when | - Not inside a development cycle (marsai:dev-cycle) - Task is documentation-only, configuration-only, or non-code - No code implementation was produced (nothing to test) - Changes are limited to CI/CD, infrastructure, or deployment configuration |
| NOT_skip_when | - "Manual testing validates all criteria" → Manual tests are not executable. Gate 3 requires unit tests. - "Integration tests are better" → Gate 3 scope is unit tests only. - "Coverage is close to 85%" → Close enough is not passing. Meet exact threshold. |
| sequence | {"after":["marsai:dev-implementation","marsai:dev-devops","marsai:dev-sre"],"before":["marsai:requesting-code-review"]} |
| related | {"complementary":["marsai:test-driven-development","marsai:qa-analyst"]} |
| input_schema | {"required":[{"name":"unit_id","type":"string","description":"Task or subtask identifier"},{"name":"acceptance_criteria","type":"array","items":"string","description":"List of acceptance criteria to test"},{"name":"implementation_files","type":"array","items":"string","description":"Files from Gate 0 implementation"},{"name":"language","type":"string","enum":["typescript","python"],"description":"Programming language"}],"optional":[{"name":"coverage_threshold","type":"float","default":85,"description":"Minimum coverage percentage (cannot be below 85)"},{"name":"gate0_handoff","type":"object","description":"Full handoff from Gate 0"},{"name":"existing_tests","type":"array","items":"string","description":"Existing test files"}]} |
| output_schema | {"format":"markdown","required_sections":[{"name":"Testing Summary","pattern":"^## Testing Summary","required":true},{"name":"Coverage Report","pattern":"^## Coverage Report","required":true},{"name":"Traceability Matrix","pattern":"^## Traceability Matrix","required":true},{"name":"Handoff to Next Gate","pattern":"^## Handoff to Next Gate","required":true}],"metrics":[{"name":"result","type":"enum","values":["PASS","FAIL"]},{"name":"coverage_actual","type":"float"},{"name":"coverage_threshold","type":"float"},{"name":"tests_written","type":"integer"},{"name":"criteria_covered","type":"string","description":"X/Y format"},{"name":"iterations","type":"integer"}]} |
| verification | {"automated":[{"command":"npm test -- --coverage | grep -E 'All files|Statements'","description":"TypeScript tests pass with coverage","success_pattern":"[8-9][0-9]|100"}],"manual":["Every acceptance criterion has at least one test","No skipped or pending tests"]} |
Ensure every acceptance criterion has at least one unit test proving it works. Follow TDD methodology: RED (failing test) -> GREEN (implementation) -> REFACTOR.
Core principle: Untested acceptance criteria are unverified claims. Each criterion MUST map to at least one executable unit test.
<block_condition>
Coverage threshold: 85% minimum (MarsAI standard). PROJECT_RULES.md can raise, not lower.
This skill ORCHESTRATES. QA Analyst Agent EXECUTES.
| Who | Responsibility |
|---|---|
| This Skill | Gather requirements, dispatch agent, track iterations |
| QA Analyst Agent | Write tests, run coverage, report results |
REQUIRED INPUT (from marsai:dev-cycle orchestrator):
<verify_before_proceed>
- unit_id exists
- acceptance_criteria is not empty
- implementation_files is not empty
- language is valid (typescript|python)
</verify_before_proceed>
```text
- unit_id: [task/subtask being tested]
- acceptance_criteria: [list of ACs to test]
- implementation_files: [files from Gate 0]
- language: [typescript|python]
OPTIONAL INPUT:
- coverage_threshold: [default 85.0, cannot be lower]
- gate0_handoff: [full Gate 0 output]
- existing_tests: [existing test files]
if any REQUIRED input is missing:
→ STOP and report: "Missing required input: [field]"
→ Return to orchestrator with error
if coverage_threshold < 85:
→ STOP and report: "Coverage threshold cannot be below MarsAI minimum (85%)"
→ Use 85% as threshold
⛔ HARD GATE: Before dispatching the QA Analyst, filter implementation_files through the testable-layer allow-list. Files outside the allow-list MUST NOT receive unit tests in this gate.
Source of truth: dev-team/docs/standards/typescript.md → "Testable Layers (MANDATORY)". This step enforces that standard at the orchestration level.
Files matching these path patterns MUST receive unit tests:
| Layer | Path pattern |
|---|---|
| Aggregates | **/domain/aggregates/**/*.ts |
| Entities | **/domain/entities/**/*.ts |
| Value Objects | **/domain/value-objects/**/*.ts |
| Services | **/app/services/**/*.ts |
| Use Cases | **/app/usecases/**/*.ts |
| Event Handlers | **/app/events/**/*.ts |
| Providers | **/infra/providers/**/*.ts |
| Gateways | **/infra/gateways/**/*.ts |
Files matching these path patterns MUST NOT receive unit tests. Attempting to create a *.spec.ts with mocks (including DummyDriver, compiled-SQL inspection, or any query-builder mock) for a file in these paths = HARD BLOCK:
| Layer | Path pattern | Why |
|---|---|---|
| Repositories | **/infra/database/**/*.ts (e.g. Kysely*Repository.ts, Prisma*Repository.ts) | Thin SQL adapters; unit-test with mocks proves the mock, not the query. Integration test only. |
| Mappers | **/infra/mappers/**/*.ts | Pure transforms — covered transitively by use case / repository tests |
| DI config | **/infra/di/**/*.ts | Boot-time glue |
| Controllers | **/infra/controllers/**/*.ts | HTTP wiring — tested via use case + integration |
| Server bootstrap | **/infra/server/**/*.ts | Verified by the app starting |
| DTOs (pure) | **/app/dtos/**/*.ts | Zod schema is its own test; no behavior to unit-test |
testable_files = []
deferred_files = []
forbidden_files = []
for each file in implementation_files:
if file matches any ALLOW-LIST pattern:
testable_files.append(file)
elif file matches any DENY-LIST repository pattern:
forbidden_files.append({ file, reason: "Repository — integration test only" })
elif file matches any other DENY-LIST pattern:
deferred_files.append({ file, reason: "[mapper/di/controller/server/dto]" })
else:
# Unknown layer — err on the side of including it
testable_files.append(file)
if testable_files is empty AND forbidden_files is non-empty:
→ Gate 3 SKIP with status: "no_testable_files"
→ Emit "Layer Allow-List Report" (see below)
→ Do NOT dispatch QA Analyst
→ Do NOT lower coverage threshold
→ Flag: if any file is in forbidden_files, note "integration test setup required"
in the handoff (to be picked up by Gate 4 or documented as infra gap)
→ Return to orchestrator with ready_for_next_gate: YES
if testable_files is non-empty:
→ Pass testable_files (NOT implementation_files) to QA Analyst in Step 3
→ Emit "Layer Allow-List Report"
Emit this block in your Gate 3 output BEFORE the Testing Summary:
## Layer Allow-List Report
| File | Layer | Action |
|------|-------|--------|
| [path] | [aggregate/entity/service/usecase/handler/provider/gateway] | Unit test (dispatched) |
| [path] | repository | Skipped — integration test only |
| [path] | mapper | Skipped — covered transitively |
| [path] | controller | Skipped — tested via use case + integration |
**Dispatched for unit tests:** [N]
**Skipped (deny-list):** [M]
**Infrastructure gap flagged:** [YES if any repository was skipped and no `*.integration.spec.ts` infrastructure exists, else NO]
| Rationalization | Why It's WRONG | Required Action |
|---|---|---|
| "I'll unit-test the repository with mocked Kysely to get coverage" | The test verifies the mock, not the query. Standards forbid this explicitly. | Skip the file. Integration tests only. |
| "Compiled-SQL inspection with DummyDriver is close enough" | It tests Kysely's builder, not your schema or data. Still mock-based. | Skip the file. Flag infra gap. |
| "I need to cover the controller to hit the coverage threshold" | Controller coverage is fake coverage. Adjust the coverage scope. | Skip the controller. Coverage scope excludes it. |
| "The task file says all implementation files should be tested" | The skill's allow-list overrides generic task instructions. | Filter through allow-list first. |
| "The file is in an unusual path, I'll unit-test it just in case" | Unknown paths default to include. Only listed deny patterns skip. | Follow the filter logic. |
| "If I don't create the test, coverage drops" | Better a missing coverage entry than a fake test. | Emit the Allow-List Report with skipped files. |
testing_state = {
unit_id: [from input],
coverage_threshold: max(85, [from input]),
coverage_actual: null,
verdict: null,
iterations: 0,
max_iterations: 3,
traceability_matrix: [],
tests_written: 0,
}
<dispatch_required agent="marsai:qa-analyst"> Write unit tests for all acceptance criteria with 85%+ coverage. </dispatch_required>
Task:
subagent_type: "marsai:qa-analyst"
description: "Write unit tests for [unit_id]"
prompt: |
⛔ WRITE UNIT TESTS for All Acceptance Criteria
## Input Context
- **Unit ID:** [unit_id]
- **Language:** [language]
- **Coverage Threshold:** [coverage_threshold]%
## Acceptance Criteria to Test
[list acceptance_criteria with AC-1, AC-2, etc.]
## Implementation Files to Test (filtered through Testable Layer Allow-List)
[list testable_files — NOT implementation_files]
**⛔ Repositories, mappers, controllers, DI config, and server bootstrap
are EXCLUDED from this list per the Testable Layers standard. Do NOT
create unit tests for them — the orchestrator already filtered them
out. See typescript.md → "Testable Layers (MANDATORY)".**
## Standards Reference
For TS: https://raw.githubusercontent.com/V4-Company/marsai/main/dev-team/docs/standards/typescript.md
Focus on: Testing Patterns section
## Requirements
### Test Coverage
- Minimum: [coverage_threshold]% branch coverage
- Every AC MUST have at least one test
- Edge cases REQUIRED (null, empty, boundary, error conditions)
### Test Naming
- TS: `describe('{Unit}', () => { it('should {scenario}', ...) })`
### Test Structure
- One behavior per test
- Arrange-Act-Assert pattern
- Mock all external dependencies
- no database/API calls (unit tests only)
### Edge Cases Required per AC Type
<cannot_skip>
- Minimum 3 edge cases per AC type
- null, empty, boundary conditions required
- Error conditions required
</cannot_skip>
| AC Type | Required Edge Cases | Minimum |
|---------|---------------------|---------|
| Input validation | null, empty, boundary, invalid format | 3+ |
| CRUD operations | not found, duplicate, concurrent | 3+ |
| Business logic | zero, negative, overflow, boundary | 3+ |
| Error handling | timeout, connection failure, retry | 2+ |
## Required Output Format
### Test Files Created
| File | Tests | Lines |
|------|-------|-------|
| [path] | [count] | +N |
### Coverage Report
**Command:** [coverage command]
**Result:**
```
[paste actual coverage output]
```
| Package/File | Coverage |
|--------------|----------|
| [name] | [X%] |
| **TOTAL** | **[X%]** |
### Traceability Matrix
| AC ID | Criterion | Test File | Test Function | Status |
|-------|-----------|-----------|---------------|--------|
| AC-1 | [criterion text] | [file] | [function] | ✅/❌ |
| AC-2 | [criterion text] | [file] | [function] | ✅/❌ |
### Quality Checks
| Check | Status |
|-------|--------|
| No skipped tests | ✅/❌ |
| No assertion-less tests | ✅/❌ |
| Edge cases per AC | ✅/❌ |
| Test isolation | ✅/❌ |
### VERDICT
**Coverage:** [X%] vs Threshold [Y%]
**VERDICT:** PASS / FAIL
If FAIL:
- **Gap Analysis:** [what needs more tests]
- **Files needing coverage:** [list with line numbers]
Parse agent output:
1. Extract coverage percentage from Coverage Report
2. Extract traceability matrix
3. Extract verdict
testing_state.coverage_actual = [extracted coverage]
testing_state.traceability_matrix = [extracted matrix]
testing_state.tests_written = [count from Test Files Created]
if verdict == "PASS" and coverage_actual >= coverage_threshold:
→ testing_state.verdict = "PASS"
→ Proceed to Step 6
if verdict == "FAIL" or coverage_actual < coverage_threshold:
→ testing_state.verdict = "FAIL"
→ testing_state.iterations += 1
→ if iterations >= max_iterations: Proceed to Step 7 (Escalate)
→ Proceed to Step 5 (Dispatch Fix)
Coverage below threshold → Return to Gate 0 for more tests
Task:
subagent_type: "[implementation_agent from Gate 0]" # e.g., "marsai:backend-engineer-typescript"
description: "Add tests to meet coverage threshold for [unit_id]"
prompt: |
⛔ COVERAGE BELOW THRESHOLD - Add More Tests
## Current Status
- **Coverage Actual:** [coverage_actual]%
- **Coverage Threshold:** [coverage_threshold]%
- **Gap:** [threshold - actual]%
- **Iteration:** [iterations] of [max_iterations]
## Gap Analysis (from QA)
[paste gap analysis from QA output]
## Files Needing Coverage
[paste files list from QA output]
## Requirements
1. Add tests to cover the identified gaps
2. Focus on edge cases and error paths
3. Run coverage after each addition
4. Stop when coverage >= [threshold]%
## Required Output
- Tests added: [list]
- New coverage: [X%]
- Coverage command output
After fix → Return to Step 3 (Re-dispatch QA Analyst)
Generate skill output:
## Testing Summary
**Status:** PASS
**Unit ID:** [unit_id]
**Iterations:** [testing_state.iterations]
## Coverage Report
**Threshold:** [coverage_threshold]%
**Actual:** [coverage_actual]%
**Status:** ✅ PASS
| Package/File | Coverage |
|--------------|----------|
[from QA output]
| **TOTAL** | **[coverage_actual]%** |
## Traceability Matrix
| AC ID | Criterion | Test | Status |
|-------|-----------|------|--------|
[from testing_state.traceability_matrix]
**Criteria Covered:** [X]/[Y] (100%)
## Quality Checks
| Check | Status |
|-------|--------|
| Coverage ≥ threshold | ✅ |
| All ACs tested | ✅ |
| No skipped tests | ✅ |
| Edge cases present | ✅ |
## Handoff to Next Gate
- Testing status: COMPLETE
- Coverage: [coverage_actual]% (threshold: [coverage_threshold]%)
- All criteria tested: ✅
- Ready for Gate 4 (Review): YES
Generate skill output:
## Testing Summary
**Status:** FAIL
**Unit ID:** [unit_id]
**Iterations:** [max_iterations] (MAX REACHED)
## Coverage Report
**Threshold:** [coverage_threshold]%
**Actual:** [coverage_actual]%
**Gap:** [threshold - actual]%
**Status:** ❌ FAIL
## Gap Analysis
[from last QA output]
## Files Still Needing Coverage
[from last QA output]
## Handoff to Next Gate
- Testing status: FAILED
- Ready for Gate 4: no
- **Action Required:** User must manually add tests or adjust scope
⛔ ESCALATION: Max iterations (3) reached. Coverage still below threshold.
User intervention required.
| Severity | Criteria | Examples |
|---|---|---|
| CRITICAL | Test infrastructure broken, no coverage possible | Test framework failure, build broken |
| HIGH | Coverage below threshold, missing AC tests | 84% coverage (below 85%), untested acceptance criteria |
| MEDIUM | Test quality issues, edge case gaps | Missing edge case tests, poor assertion messages |
| LOW | Test naming, documentation gaps | Non-standard test names, missing test descriptions |
Report all severities. CRITICAL/HIGH = immediate fix. MEDIUM = fix in iteration. LOW = document for follow-up.
See shared-patterns/shared-pressure-resistance.md for universal pressure scenarios.
| User Says | Your Response |
|---|---|
| "84% is close enough" | "85% is minimum threshold. 84% = FAIL. Adding more tests." |
| "Manual testing covers it" | "Gate 3 requires executable unit tests. Dispatching QA analyst." |
| "Skip testing, deadline" | "Testing is MANDATORY. Untested code = unverified claims." |
See shared-patterns/shared-anti-rationalization.md for universal anti-rationalizations.
| Rationalization | Why It's WRONG | Required Action |
|---|---|---|
| "Tool shows 83% but real is 90%" | Tool output IS real. Your belief is not. | Fix issue, re-measure |
| "Excluding dead code gets us to 85%" | Delete dead code, don't exclude it. | Delete dead code |
| "84.5% rounds to 85%" | Rounding is not allowed. 84.5% < 85%. | Write more tests |
| "Close enough with all AC tested" | "Close enough" is not passing. | Meet exact threshold |
| "Integration tests cover this" | Gate 3 = unit tests only. Different scope. | Write unit tests |
| Type | Characteristics | Gate 3? |
|---|---|---|
| Unit ✅ | Mocks all external deps, tests single function | YES |
| Integration ❌ | Hits real database/API/filesystem | no |
## Testing Summary
**Status:** [PASS|FAIL]
**Unit ID:** [unit_id]
**Duration:** [Xm Ys]
**Iterations:** [N]
## Coverage Report
**Threshold:** [X%]
**Actual:** [Y%]
**Status:** [✅ PASS | ❌ FAIL]
## Traceability Matrix
| AC ID | Criterion | Test | Status |
|-------|-----------|------|--------|
| AC-1 | [text] | [test] | ✅/❌ |
**Criteria Covered:** [X/Y]
## Handoff to Next Gate
- Testing status: [COMPLETE|FAILED]
- Coverage: [X%]
- Ready for Gate 4: [YES|no]