Skip to main content

accordant-quickref

Quick reference and cheatsheet for Accordant API - use this skill for quick syntax lookup or code snippets

Source facts

Repository
microsoft/accordant
Last source activity
June 10, 2026 at 17:20
Detected SKILL.md language
English
Stars
68
Forks
9

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
accordant-quickref
description
Quick reference and cheatsheet for Accordant API - use this skill for quick syntax lookup or code snippets
# Accordant Quick Reference ## State Definition ```csharp [State] public partial class MyState { public Dictionary<string, decimal> Balances { get; set; } = new(); public Dictionary<string, UserState> Users { get; set; } = new(); } [State] public partial class UserState { public string Name { get; set; } = string.Empty; public List<string> Tags { get; set; } = new(); } ``` ## Create a Spec ```csharp var spec = new Spec<MyState>() .WithJsonPrinters(); // Optional: nice logging ``` ## Define Operations ### Inline Syntax ```csharp spec.Operation<TRequest, TResponse>("OperationName", (request, state) => { // Return ExpectedOutcomes }); ``` ### Examples ```csharp // Simple request (single value) spec.Operation<string, ApiResult<User>>("GetUser", (userId, state) => { ... }); // Tuple request (multiple values) spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Deposit", (request, state) => { var (id, amount) = request; // Destructure // ... }); // Class-based request spec.Operation<CreateUserRequest, ApiResult<User>>("CreateUser", (request, state) => { ... }); ``` ## Expected Outcomes ### Basic Expectation ```csharp Expect.That<TResponse>(response => /* predicate */) ``` ### With Explanation (Recommended) ```csharp Expect.That<ApiResult<decimal>>( r => r.IsSuccess && r.Data == expectedValue, $"Expected success with value {expectedValue}") ``` ### With ValidationResult ```csharp Expect.That<User>(response => { if (response.Name != expected) return ValidationResult.Invalid($"Name mismatch: {response.Name}"); return ValidationResult.Valid(); }) ``` ### Exception Expectation ```csharp Expect.Throws<NotFoundException>("Resource not found") ``` ### Multiple Valid Outcomes ```csharp Expect.OneOf( Expect.That<T>(r => /* outcome 1 */).ThenState(...), Expect.That<T>(r => /* outcome 2 */).SameState(), Expect.That<T>(r => /* outcome 3 */).ThenState(...) ) ``` ## State Transitions ### No Change ```csharp .SameState() ``` ### State Changes ```csharp .ThenState<MyState>(nextState => nextState.Items[id] = newValue) ``` ### Response-Dependent State ```csharp .ThenState<MyState>( (TResponse response, MyState nextState) => nextState.Items[response.Id] = new Item { ... }, mock: () => new TResponse { Id = Guid.NewGuid().ToString() }) ``` ## Async Operations ```csharp .ThenState<MyState>(next => next.Jobs[id] = JobStatus.Pending) .Triggers(AsyncOperation.Create<MyState>( isTerminal: s => s.Jobs[id] != JobStatus.Pending, transitions: new Action<MyState>[] { next => next.Jobs[id] = JobStatus.Completed, next => next.Jobs[id] = JobStatus.Failed } )) ``` ## Bind Execution ```csharp spec.ExecuteWith<ApiClient>() .Bind<TRequest, TResponse>("OperationName", (client, request) => client.Method(request).Result) .BindAsync<TRequest, TResponse>("AsyncOperation", async (client, request) => await client.MethodAsync(request)); ``` ## Test Generation ### Define Inputs ```csharp var inputs = new InputSet { spec.GetOperation<string, ApiResult<User>>("CreateUser").With("alice", "Create Alice"), spec.GetOperation<(string, decimal), ApiResult<decimal>>("Deposit").With(("alice", 100m), "Deposit 100"), }; ``` ### Generate Tests ```csharp var testCases = spec.GenerateTests(initialState, inputs, new TestGenerationOptions { MaxDepth = 5, StateConstraint = state => ((MyState)state).Items.Count <= 3 }); ``` ### Run Tests ```csharp var context = spec.CreateTestingContext(); context.Register(new ApiClient(httpClient)); var results = await spec.RunTests(context, initialState, testCases, new TestExecutionOptions { BeforeEachAsync = async _ => await ResetDatabase() }); Assert.That(results.All(r => r.Success)); ``` ## Concurrent Tests ```csharp var concurrentTestCases = spec.GenerateConcurrentTests(initialState, inputs, new TestGenerationOptions { MaxDepth = 4 }); var results = await spec.RunTests(context, initialState, concurrentTestCases, new TestExecutionOptions { ... }); ``` ## Manual Conformance Testing ```csharp var stateProfile = new StateProfile(initialState); var response = await client.CreateUser("alice"); (bool isValid, string message, stateProfile) = spec.Allows(createUserOp, "alice", response, stateProfile); Assert.IsTrue(isValid, message); ``` ## Visualization ```csharp var dot = spec.VisualizeStateSpace(initialState, inputs, options); File.WriteAllText("graph.dot", dot); // Convert: dot -Tpng graph.dot -o graph.png ``` ## TestGenerationOptions | Option | Type | Default | Description | |--------|------|---------|-------------| | `MaxDepth` | int | 5 | Max sequence length | | `StateConstraint` | Func<State, bool> | null | Prune states | | `MaxConcurrencyLevel` | int | 3 | Concurrent ops | | `SequentialTestCaseAlgorithm` | delegate | StateCoverage | Walk algorithm | ## Test Case Algorithms ```csharp // State coverage (default) SequentialTestCaseAlgorithms.StateCoverage // Transition coverage SequentialTestCaseAlgorithms.CreateTransitionCoverage(maxSequenceLength: 4) // Random walk SequentialTestCaseAlgorithms.CreateRandomWalk(numberOfWalks: 100, maxWalkLength: 8, seed: 42) ``` ## Common Operation Pattern ```csharp spec.Operation<(string Id, decimal Amount), ApiResult<decimal>>("Withdraw", (request, state) => { var (accountId, amount) = request; // Guard 1: Resource exists? if (!state.Accounts.TryGetValue(accountId, out var balance)) return Expect.That<ApiResult<decimal>>(r => r.IsNotFound, "Account not found") .SameState(); // Guard 2: Business rule if (balance < amount) return Expect.That<ApiResult<decimal>>(r => r.IsBadRequest, "Insufficient funds") .SameState(); // Success path var newBalance = balance - amount; return Expect.That<ApiResult<decimal>>( r => r.IsSuccess && r.Data == newBalance, $"Expected new balance {newBalance}") .ThenState<BankState>(next => next.Accounts[accountId] = newBalance); }); ``` ## Namespace ```csharp using Microsoft.Accordant; ``` ## NuGet Package ```bash dotnet add package Microsoft.Accordant ```
View on GitHub