Code Testing Extensions
.NET (Microsoft)OfficialPublished by .NET (Microsoft)
- Skill
- Guidelines
- Software development
- MIT
- Low risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
Code Testing Extensions is a non-invocable reference library designed to support automated testing workflows. It provides a structured collection of documentation files covering various programming languages, including .NET, Python, TypeScript, Go, Java, and more. Each entry offers essential guidance on build and test commands, framework-specific patterns, mocking strategies, and common error resolution. Additionally, the catalog includes example files that demonstrate complete testing pipeline cycles, from research and planning to test generation and reporting.
What it does
- Provides language-specific testing guidance for multiple programming environments.
- Lists standard build and test commands for various testing frameworks.
- Offers best practices for mocking, project layout, and framework detection.
- Includes concrete examples of full testing pipeline workflows.
- Serves as a centralized reference for agents to ensure consistent testing standards.
When to use it
- When an agent needs to determine the correct testing commands for a specific language.
- When implementing or debugging a testing pipeline for a new project.
- When guidance on framework-specific mocking or test structure is required.
- When looking for representative examples of a complete test generation cycle.
Advantages
- Ensures consistency across different testing environments.
- Reduces ambiguity by providing standardized commands and patterns.
- Provides both high-level guidance and concrete implementation examples.
- Supports a wide range of modern programming languages and frameworks.
Usage examples
- “Read extensions/python.md to understand the preferred testing patterns for a pytest project.”
- The agent retrieves the Python-specific guidance, identifying the correct test runner commands and mocking strategies to apply.
- “Consult extensions/java-examples.md to see how to structure a JUnit 5 test suite.”
- The agent reviews the provided example to replicate the established project structure and testing conventions for the Java codebase.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/dotnet/code-testing-extensions/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip code-testing-extensions.zip -d .agents/skills
Documentation by .NET (Microsoft)
Code Testing Extensions
This reference-only catalog lists bundled guidance for the code-testing pipeline. Read the matching file directly; do not invoke this catalog as a skill. Resource paths are relative to this catalog, not the project workspace.
Available Extension Files
| File | Language | Contents |
|---|---|---|
| extensions/dotnet.md | .NET (C#/F#/VB) | Build commands, test commands, project reference validation, common CS error codes, MSTest template |
| extensions/python.md | Python | Framework-adaptive test commands (pytest, custom runners), project layout detection, mocking guidelines, common errors |
| extensions/typescript.md | TypeScript/JavaScript | Build/test commands (Jest/Vitest/Mocha), framework detection, mocking, TS-specific considerations |
| extensions/powershell.md | PowerShell | Test commands (Pester v5), module import patterns, discovery/run pitfalls, mocking, common errors |
| extensions/cpp.md | C++ | Testing internals with friend declarations |
| extensions/go.md | Go | go test commands, table-driven tests, integration vs unit layout, mocking via interfaces, common errors |
| extensions/java.md | Java | Maven/Gradle commands, JUnit 4/5 and TestNG detection, Mockito, Spring Boot slices, common errors |
| extensions/rust.md | Rust | cargo test commands, unit vs integration vs doc tests, features, async test harnesses, common errors |
| extensions/ruby.md | Ruby | RSpec and Minitest commands, Bundler usage, Rails specifics, mocking patterns, common errors |
| extensions/swift.md | Swift | SPM and Xcode test commands, XCTest vs Swift Testing, @testable import, async/throws tests, common errors |
| extensions/kotlin.md | Kotlin | Gradle commands, JUnit/Kotest detection, MockK, coroutines test, KMP and Android specifics, common errors |
| extensions/dotnet-examples.md | .NET (C#/F#/VB) | Concrete pipeline examples: sample research output, plan, generated tests, fix cycles, final report |
| extensions/python-examples.md | Python | Concrete pipeline examples (pytest): research, plan, generated test file, fix cycles, final report |
| extensions/typescript-examples.md | TypeScript/JavaScript | Concrete pipeline examples (Vitest, applicable to Jest): research, plan, generated test file, fix cycles, final report |
| extensions/go-examples.md | Go | Concrete pipeline examples (standard testing): research, plan, table-driven test file, fix cycles, final report |
| extensions/java-examples.md | Java | Concrete pipeline examples (JUnit 5 + Mockito on Maven): research, plan, generated test file, fix cycles, final report |
Usage
Read the appropriate base extension before writing test code. Load an
<language>-examples.md file only when the repository has no representative
tests and the base extension does not resolve the needed pattern. Do not load
end-to-end examples for a focused request with established local conventions.
Files
- ATTRIBUTION.mdAdded by AutoGineer857 B
- LICENSELicence file added by AutoGineer1.1 KiB
- SKILL.md3.7 KiB
- extensions/cpp-examples.md9.1 KiB
- extensions/cpp.md20.1 KiB
- extensions/dotnet-examples.md10.7 KiB
- extensions/dotnet.md10.5 KiB
- extensions/go-examples.md12.4 KiB
- extensions/go.md7.8 KiB
- extensions/java-examples.md11.9 KiB
- extensions/java.md9.7 KiB
- extensions/kotlin-examples.md10.3 KiB
- extensions/kotlin.md11.2 KiB
- extensions/powershell-examples.md9.1 KiB
- extensions/powershell.md12.1 KiB
- extensions/python-examples.md12.1 KiB
- extensions/python.md11.7 KiB
- extensions/ruby-examples.md8.9 KiB
- extensions/ruby.md14.7 KiB
- extensions/rust-examples.md10.6 KiB
- extensions/rust.md8.8 KiB
- extensions/swift.md9.4 KiB
- extensions/typescript-examples.md12.7 KiB
- extensions/typescript.md7.9 KiB
extensions/typescript-examples.md
TypeScript Pipeline Examples
Concrete input→output examples for the test generation pipeline targeting a TypeScript codebase using Vitest. These show what each pipeline phase produces for a small project.
Jest, Mocha, and node:test follow the same shape. Replace
vi.fn()/vi.mock()withjest.fn()/jest.mock()(Jest) or hand-written stubs (node:test/Mocha) and adjust the runner command accordingly.
Source Under Test
A simple InvoiceService in a TypeScript library using Vitest:
src/
invoiceService.ts
invoice.ts
invoiceRepository.ts
index.ts (re-exports public API)
package.json
tsconfig.json
vitest.config.ts
package-lock.json (committed for reproducible installs)// src/invoiceService.ts
import { Invoice, InvoiceStatus } from "./invoice";
import { InvoiceRepository } from "./invoiceRepository";
export class InvoiceService {
constructor(private readonly repository: InvoiceRepository) {}
calculateTotal(invoice: Invoice): number {
if (invoice == null) throw new TypeError("invoice must not be null");
if (invoice.lineItems.length === 0) {
throw new Error("Invoice has no line items.");
}
const subtotal = invoice.lineItems.reduce(
(acc, li) => acc + li.quantity * li.unitPrice,
0,
);
const tax = subtotal * invoice.taxRate;
return roundTo2(subtotal + tax);
}
async getById(id: number): Promise<Invoice> {
const invoice = await this.repository.find(id);
if (invoice == null) {
throw new Error(`Invoice ${id} not found.`);
}
return invoice;
}
async markAsPaid(id: number): Promise<void> {
const invoice = await this.repository.find(id);
if (invoice == null) {
throw new Error(`Invoice ${id} not found.`);
}
if (invoice.status === InvoiceStatus.Paid) {
throw new Error("Invoice is already paid.");
}
invoice.status = InvoiceStatus.Paid;
invoice.paidDate = new Date();
await this.repository.update(invoice);
}
}
function roundTo2(n: number): number {
return Math.round((n + Number.EPSILON) * 100) / 100;
}Sample Research Output
What code-testing-researcher produces in <TESTAGENT_DIR>/research.md:
# Test Generation Research
## Project Overview
- **Path**: /work/contoso-billing
- **Language**: TypeScript 5.4
- **Module system**: ESM (`"type": "module"` in package.json)
- **Test Framework**: Vitest 1.x (detected via `vitest.config.ts` and `devDependencies.vitest`)
- **Package Manager**: npm (lockfile = `package-lock.json`)
## Coverage Baseline
- **Initial Line Coverage**: unknown
- **Strategy**: broad
- **Existing Test Count**: 0 tests across 0 files
## Build & Test Commands
- **Install**: `npm ci`
- **Type-check**: `npx tsc --noEmit`
- **Test**: `npx vitest run` (NEVER bare `vitest` — that starts watch mode)
- **Lint**: none configured
## Project Structure
- Source: `src/`
- Tests: none (will colocate as `src/invoiceService.test.ts` to match Vitest defaults)
## Files to Test
### High Priority
| File | Classes/Functions | Testability | Notes |
|------|-------------------|-------------|-------|
| src/invoiceService.ts | InvoiceService: calculateTotal, getById, markAsPaid | High | Core business logic, repository dependency needs mocking |
### Low Priority / Skip
| File | Reason |
|------|--------|
| src/invoice.ts | Type definitions and enum |
| src/invoiceRepository.ts | Interface only |
| src/index.ts | Re-export barrel |
## Existing Tests
- No existing tests found
## Testing Patterns
- No existing patterns; recommend `describe`/`it` blocks, `vi.fn()` stubs for the repository interface, and `it.each` for table-driven cases.
## Recommendations
- Co-locate test next to source (`src/invoiceService.test.ts`) — matches Vitest defaults and avoids reaching into `../src/`
- Use a fake-timers helper (`vi.useFakeTimers()`) to control `new Date()` in `markAsPaid`
- Use a type-narrowed mock object (`{ find: vi.fn(), update: vi.fn() } satisfies InvoiceRepository`) rather than full module mockingSample Plan Output
What code-testing-planner produces in <TESTAGENT_DIR>/plan.md:
# Test Implementation Plan
## Overview
Generate Vitest tests for InvoiceService, covering all three public methods
across happy path, edge case, and error scenarios. Single phase since there is
only one source file.
## Commands
- **Install**: `npm ci`
- **Type-check**: `npx tsc --noEmit`
- **Test (file-scoped during dev)**: `npx vitest run src/invoiceService.test.ts`
- **Test (full)**: `npx vitest run`
## Phase Summary
| Phase | Focus | Files | Est. Tests |
|-------|-------|-------|------------|
| 1 | InvoiceService | 1 | 9-12 |
---
## Phase 1: InvoiceService
### Overview
Cover all public methods of InvoiceService. `calculateTotal` is pure logic tested
with `it.each`. Async methods require a fake repository.
### Files to Test
#### 1. invoiceService.ts
- **Source**: `src/invoiceService.ts`
- **Test File**: `src/invoiceService.test.ts`
**Methods to Test**:
1. `calculateTotal` — Pure calculation logic
- Happy path: single line item returns quantity × price + tax
- Happy path: multiple line items summed correctly
- Edge case: zero tax rate returns subtotal only
- Error case: null invoice throws TypeError
- Error case: empty line items throws Error
2. `getById` — Repository lookup
- Happy path: existing ID returns invoice
- Error case: missing ID rejects with Error
3. `markAsPaid` — State transition
- Happy path: pending invoice transitions to Paid with `paidDate` set
- Error case: already-paid rejects with Error
- Error case: missing ID rejects with Error
### Success Criteria
- [ ] Test file created at `src/invoiceService.test.ts`
- [ ] `npx tsc --noEmit` succeeds
- [ ] `npx vitest run` reports all tests passed
- [ ] No real network/timers — repository is a `vi.fn()` fake, `new Date()` is controlled via fake timersSample Generated Test File
What code-testing-implementer produces:
// src/invoiceService.test.ts
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { Invoice, InvoiceStatus } from "./invoice";
import type { InvoiceRepository } from "./invoiceRepository";
import { InvoiceService } from "./invoiceService";
function makeRepository(): InvoiceRepository & { find: ReturnType<typeof vi.fn>; update: ReturnType<typeof vi.fn> } {
return {
find: vi.fn(),
update: vi.fn(),
};
}
describe("InvoiceService", () => {
let repository: ReturnType<typeof makeRepository>;
let sut: InvoiceService;
beforeEach(() => {
repository = makeRepository();
sut = new InvoiceService(repository);
});
// --- calculateTotal ---
describe("calculateTotal", () => {
it.each([
{ quantity: 1, unitPrice: 100, taxRate: 0.1, expected: 110 },
{ quantity: 3, unitPrice: 25, taxRate: 0, expected: 75 },
{ quantity: 2, unitPrice: 9.99, taxRate: 0.07, expected: 21.38 },
])(
"returns $expected for $quantity × $unitPrice with tax $taxRate",
({ quantity, unitPrice, taxRate, expected }) => {
const invoice: Invoice = {
id: 1,
status: InvoiceStatus.Pending,
taxRate,
lineItems: [{ quantity, unitPrice }],
};
expect(sut.calculateTotal(invoice)).toBe(expected);
},
);
it("throws TypeError when invoice is null", () => {
expect(() => sut.calculateTotal(null as unknown as Invoice)).toThrow(TypeError);
});
it("throws when line items are empty", () => {
const invoice: Invoice = {
id: 1,
status: InvoiceStatus.Pending,
taxRate: 0,
lineItems: [],
};
expect(() => sut.calculateTotal(invoice)).toThrow("no line items");
});
});
// --- getById ---
describe("getById", () => {
it("returns the invoice for an existing id", async () => {
const expected: Invoice = { id: 42, status: InvoiceStatus.Pending, taxRate: 0, lineItems: [] };
repository.find.mockResolvedValue(expected);
await expect(sut.getById(42)).resolves.toBe(expected);
expect(repository.find).toHaveBeenCalledWith(42);
});
it("rejects with Error when the id is missing", async () => {
repository.find.mockResolvedValue(null);
await expect(sut.getById(999)).rejects.toThrow(/999/);
});
});
// --- markAsPaid ---
describe("markAsPaid", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2025-01-01T12:00:00.000Z"));
});
afterEach(() => {
vi.useRealTimers();
});
it("transitions a pending invoice to Paid with paidDate set", async () => {
const invoice: Invoice = {
id: 1,
status: InvoiceStatus.Pending,
taxRate: 0,
lineItems: [],
};
repository.find.mockResolvedValue(invoice);
repository.update.mockResolvedValue(undefined);
await sut.markAsPaid(1);
expect(invoice.status).toBe(InvoiceStatus.Paid);
expect(invoice.paidDate).toEqual(new Date("2025-01-01T12:00:00.000Z"));
expect(repository.update).toHaveBeenCalledWith(invoice);
});
it("rejects when the invoice is already paid", async () => {
const invoice: Invoice = {
id: 1,
status: InvoiceStatus.Paid,
taxRate: 0,
lineItems: [],
};
repository.find.mockResolvedValue(invoice);
await expect(sut.markAsPaid(1)).rejects.toThrow("already paid");
expect(repository.update).not.toHaveBeenCalled();
});
it("rejects when the id is missing", async () => {
repository.find.mockResolvedValue(null);
await expect(sut.markAsPaid(999)).rejects.toThrow(/999/);
});
});
});Sample Fix Cycle
When the implementer encounters a runner or type error, the fixer agent diagnoses and resolves it.
Test output:
Error: Vitest failed to access its internal state.
One of the following is possible:
- "vitest" is imported directly without running "vitest" commandFixer diagnosis: The agent ran node src/invoiceService.test.ts (or bare vitest, which is watch-mode). The runner must be invoked via npx vitest run.
Fix applied:
# Wrong — bare vitest starts an interactive watcher in CI
npx vitest
# Right — `run` is the one-shot command
npx vitest runRerun: SUCCESS
Another common cycle — ESM/CJS mismatch:
Test output:
SyntaxError: Cannot use import statement outside a moduleFixer diagnosis: The project's tsconfig.json emits ESM ("module": "NodeNext") but package.json has no "type": "module". Vitest happens to handle this natively; switching to Jest would require additional configuration. The fix here is to ensure Vitest is the runner being used (as already configured in vitest.config.ts) and avoid recompiling test files through a separate non-ESM-aware tool.
Fix applied: Use npx vitest run (which uses esbuild internally and handles both ESM and CJS) instead of compiling with tsc and running the emitted .js directly.
Rerun: SUCCESS
Another common cycle — wrong mock typing:
Build output:
src/invoiceService.test.ts:14:5 - error TS2322: Type '{ find: Mock<any, any>; }' is not assignable to type 'InvoiceRepository'.
Property 'update' is missing in type '{ find: Mock<any, any>; }' but required in type 'InvoiceRepository'.Fixer diagnosis: The fake repository only stubbed find, not update. The InvoiceRepository interface requires both. TypeScript caught this at compile time.
Fix applied:
// Before
const repository = { find: vi.fn() } as InvoiceRepository;
// After — provide both methods, narrow the return type so the test code keeps autocomplete
function makeRepository(): InvoiceRepository & { find: ReturnType<typeof vi.fn>; update: ReturnType<typeof vi.fn> } {
return { find: vi.fn(), update: vi.fn() };
}Rebuild + rerun: SUCCESS
Sample Final Report
What test-engineer produces at Step 9:
## Test Generation Report
**Project**: contoso-billing (TypeScript)
**Strategy**: Direct (single source file in scope)
### Results
| Metric | Value |
|----------------|-------|
| Tests created | 9 |
| Tests passing | 9 |
| Tests failing | 0 |
| Files created | 1 |
### Files Created
- `src/invoiceService.test.ts` (9 tests, 3 parameterized via `it.each`)
### Coverage
- InvoiceService.calculateTotal — 3 happy path, 2 error cases
- InvoiceService.getById — 1 happy path, 1 error case
- InvoiceService.markAsPaid — 1 happy path, 2 error cases
### Build / Test Validation
- Install: ✅ `npm ci`
- Type-check: ✅ `npx tsc --noEmit`
- Test run: ✅ `npx vitest run`
### Next Steps
- Add tests for any HTTP/Express adapters once they exist
- Consider property-based testing (`fast-check`) for `calculateTotal` roundingRequirements and compatibility
Written for: Claude Code
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Claude Code frontmatter, Needs Python
Security
What our scanner noticed· Low risk
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- .NET (Microsoft)
- Publisher
- .NET (Microsoft) (Official)
- Source
- dotnet/skills · plugins/dotnet-test/skills/code-testing-extensions · commit 96c3d68
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by .NET (Microsoft) or .NET (Microsoft).
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download code-testing-extensions.zip