一键导入
contract-testing
// Use when authoring OpenAPI/AsyncAPI contracts, generating Microcks samples, setting up Testcontainers mocks, verifying provider contracts, or bridging API contracts across DESIGN → DISTILL → DELIVER phases.
// Use when authoring OpenAPI/AsyncAPI contracts, generating Microcks samples, setting up Testcontainers mocks, verifying provider contracts, or bridging API contracts across DESIGN → DISTILL → DELIVER phases.
Install the full eleven-workflow skraft SDLC pipeline (discover → discuss → design → distill → deliver, each with an automated reviewer) into the current repo in one pass. Use when the user wants an end-to-end agent pipeline driven by a single issue label, or types /install-skraft-pipeline.
Use when reviewing DISTILL artefacts (Gherkin scenarios, test plans, implementation plans) for quality, completeness, and alignment. Contains the gate definitions and scoring rubric for the acceptance-designer-reviewer lenses.
Use when documenting architecture decisions as ADRs, evaluating trade-offs between alternatives, or managing the lifecycle of existing decisions. Covers ADR template, status transitions, consequence analysis, and quality criteria.
Use when selecting architecture patterns for a new feature, performing Event Modeling, defining bounded contexts, choosing DDD tactical patterns, evaluating pattern fitness, or understanding how patterns compose. Covers Event Modeling methodology, DDD strategic design, DDD tactical patterns, Clean Architecture, CQRS, and Event Sourcing.
Use when reviewing DESIGN artefacts (event models, ADRs, component diagrams, context maps, interface contracts) for quality, DDD compliance, and architectural correctness. Contains gate definitions and scoring rubric for the solution-architect-reviewer lenses.
Use when writing, reviewing, or structuring BDD scenarios in Gherkin format. Covers Given/When/Then conventions, scenario outline patterns, background usage, tag strategies, and domain language alignment. Load before any Gherkin authoring.
| name | contract-testing |
| description | Use when authoring OpenAPI/AsyncAPI contracts, generating Microcks samples, setting up Testcontainers mocks, verifying provider contracts, or bridging API contracts across DESIGN → DISTILL → DELIVER phases. |
Contract-first API development spans three SDLC phases. Each phase produces specific artifacts consumed by the next.
DESIGN DISTILL DELIVER
OpenAPI / AsyncAPI → Microcks samples → Testcontainers mocks
contracts/{api}.yaml .apiexamples.yaml MicrocksContainer
.apimetadata.yaml + VerifyAsync()
Artifact path convention:
.skraft/sdlc/design/contracts/{api-name}.yaml.skraft/sdlc/distill/contracts/{api-name}.apiexamples.yaml
.skraft/sdlc/distill/contracts/{api-name}.apimetadata.yamlCore principle: the contract is the source of truth. Implementation is verified against it, not the other way around.
Write OpenAPI 3.1 contracts in YAML. Store at .skraft/sdlc/design/contracts/{api-name}.yaml.
Required top-level structure:
openapi: 3.1.0
info:
title: {Human Readable API Name}
version: 1.0.0
description: {One sentence purpose}
paths:
/resource/{id}:
get:
operationId: getResourceById
summary: {Brief summary}
parameters: [...]
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/ResourceResponse"
"404":
description: Not found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
components:
schemas:
ResourceResponse:
type: object
required: [id, status]
properties:
id:
type: string
status:
type: string
ErrorResponse:
type: object
required: [code, message]
properties:
code:
type: string
message:
type: string
Versioning rules:
info.version on any breaking change (removed field, changed type, removed operation).{api-name}-v{major}.yaml for major version coexistence.File naming: kebab-case, matching the bounded context and resource. Example: eligibility-check-api.yaml.
Produce two files per contract:
.apiexamples.yaml — response examples per operationapiVersion: mocks.microcks.io/v1alpha1
kind: APIExamples
metadata:
name: "{API Title} - {version}"
spec:
examples:
{operationId}:
"{Example Name}":
request:
parameters:
{paramName}: "{value}"
body: |
{JSON body if POST/PUT}
response:
code: 200
headers:
Content-Type: application/json
body: |
{
"field": "value"
}
Rules:
metadata.name must match the info.title + info.version from the OpenAPI contract exactly.request.parameters holds path and query params as string values.response.code is an integer..apimetadata.yaml — dispatcher configurationapiVersion: mocks.microcks.io/v1alpha1
kind: APIMetadata
metadata:
name: "{API Title} - {version}"
spec:
operations:
- name: "{HTTP_METHOD} /path/{param}"
dispatcher: JSON_BODY | JS | GROOVY
dispatcherRules: |
{dispatcher-specific rules}
Dispatcher selection:
JSON_BODY — route on a request body JSON field value. Use for simple request matching.JS — route using a JavaScript function. Use when routing logic is conditional or multi-field.GROOVY — route using Groovy DSL. Use for stateful mocks (in-memory counters, delay simulation).JSON_BODY dispatcher rules format:
exp=$.fieldName cases=VALUE_A:ExampleName1&&VALUE_B:ExampleName2
JS dispatcher rules format:
function dispatch(request) {
var body = JSON.parse(request.body);
if (body.field === "value") return "ExampleName";
return "DefaultExample";
}
GROOVY dispatcher rules format:
def body = new groovy.json.JsonSlurper().parseText(request.body)
if (body.field == "value") return "ExampleName"
return "DefaultExample"
Use the Microcks.Testcontainers NuGet package.
NuGet packages:
Microcks.Testcontainers
Testcontainers
Single-service setup (IAsyncLifetime):
public class EligibilityApiTests : IAsyncLifetime
{
private MicrocksContainer _microcks = null!;
public async Task InitializeAsync()
{
_microcks = await new MicrocksBuilder()
.WithMainArtifact("contracts/eligibility-check-api.yaml")
.WithMainArtifact("contracts/eligibility-check-api.apiexamples.yaml")
.BuildAsync();
}
public async Task DisposeAsync() => await _microcks.DisposeAsync();
[Fact]
public async Task Should_return_eligible_driver()
{
var mockUrl = _microcks.GetRestMockUrl("Eligibility Check API", "1.0.0");
// use mockUrl as base address in HttpClient
}
}
WebApplicationFactory integration:
public class ApiFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
private MicrocksContainer _microcks = null!;
public async Task InitializeAsync()
{
_microcks = await new MicrocksBuilder()
.WithMainArtifact("contracts/eligibility-check-api.apiexamples.yaml")
.BuildAsync();
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
// Replace real HTTP client with Microcks mock URL
var mockUrl = _microcks.GetRestMockUrl("Eligibility Check API", "1.0.0");
services.AddHttpClient<IEligibilityClient, EligibilityClient>(
c => c.BaseAddress = new Uri(mockUrl));
});
}
public async Task DisposeAsync()
{
await _microcks.DisposeAsync();
await base.DisposeAsync();
}
}
Collection fixture for shared Microcks instance (multiple test classes):
[CollectionDefinition("Microcks")]
public class MicrocksCollection : ICollectionFixture<MicrocksFixture> { }
public class MicrocksFixture : IAsyncLifetime
{
public MicrocksContainer Container { get; private set; } = null!;
public async Task InitializeAsync()
{
Container = await new MicrocksBuilder()
.WithMainArtifact("contracts/eligibility-check-api.apiexamples.yaml")
.BuildAsync();
}
public async Task DisposeAsync() => await Container.DisposeAsync();
}
Use VerifyAsync() to assert your implementation satisfies the contract.
var result = await _microcks.VerifyAsync("Eligibility Check API", "1.0.0");
Assert.True(result.Success, string.Join("\n", result.Failures));
TestResult properties:
result.Success → bool — true only when all contract operations pass.result.Failures → IList<string> — descriptions of each failing assertion.What "verified" means: every example in .apiexamples.yaml was replayed against your running service; all response codes, headers, and body fields matched.
CI gate rule: call VerifyAsync in a dedicated test and fail the build if result.Success == false. Do not suppress failures.
Write AsyncAPI 2.6.0 contracts. Store at .skraft/sdlc/design/contracts/{event-name}-events.yaml.
Required structure:
asyncapi: 2.6.0
info:
title: {Event API Title}
version: 1.0.0
channels:
{topic-or-queue-name}:
subscribe:
operationId: on{EventName}
message:
$ref: "#/components/messages/{EventName}"
publish:
operationId: publish{EventName}
message:
$ref: "#/components/messages/{EventName}"
components:
messages:
{EventName}:
name: {EventName}
payload:
type: object
required: [eventId, occurredAt]
properties:
eventId:
type: string
format: uuid
occurredAt:
type: string
format: date-time
Kafka bindings:
channels:
eligibility.checked:
bindings:
kafka:
groupId: eligibility-consumer-group
clientId: eligibility-checker
Consumer test pattern: subscribe to topic → publish test message via Microcks → assert message received by consumer.
Producer test pattern: trigger use case → assert event published on topic via Microcks verification.
Artifacts flow from DESIGN → DISTILL → DELIVER following this convention:
| Phase | Artifact | Path |
|---|---|---|
| DESIGN | OpenAPI contract | .skraft/sdlc/design/contracts/{name}.yaml |
| DESIGN | AsyncAPI contract | .skraft/sdlc/design/contracts/{name}-events.yaml |
| DISTILL | Microcks examples | .skraft/sdlc/distill/contracts/{name}.apiexamples.yaml |
| DISTILL | Microcks metadata | .skraft/sdlc/distill/contracts/{name}.apimetadata.yaml |
| DELIVER | Test imports | Via MicrocksBuilder.WithMainArtifact(path) referencing DISTILL artifacts |
Import order for MicrocksBuilder: always load the OpenAPI/AsyncAPI contract first (schema), then the .apiexamples.yaml (examples), then the .apimetadata.yaml (dispatcher config).
Version bump protocol:
info.version in the contract YAML.metadata.name in both DISTILL artifacts to match.VerifyAsync("Name", "version") calls in tests.Use MicrocksContainersEnsemble when the service under test calls multiple downstream APIs.
var ensemble = await new MicrocksContainersEnsembleBuilder()
.WithMainArtifact("contracts/eligibility-check-api.apiexamples.yaml")
.WithMainArtifact("contracts/driver-profile-api.apiexamples.yaml")
.BuildAsync();
var eligibilityMockUrl = ensemble.GetRestMockUrl("Eligibility Check API", "1.0.0");
var driverMockUrl = ensemble.GetRestMockUrl("Driver Profile API", "1.0.0");
Docker Compose variant: supply a docker-compose.yaml with dependent services and pass it to the ensemble builder for full integration environment startup.
.apiexamples.yaml full spec, all dispatcher types, templatingVerifyAsync() patterns, TestResult, CI gate integrationExamples: