.github/skills/policy-testing/SKILL.md
Conventions and patterns for writing policy compilation tests in the Azure API Management policy toolkit. Use this skill when creating or modifying test files in test/Test.Core/Compiling/.
npx skillsauth add azure/azure-api-management-policy-toolkit policy-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill describes how to write tests for policy compilation in the Azure API Management policy toolkit.
test/Test.Core/Compiling/{PolicyName}Tests.cs// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
namespace Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling;
[TestClass]
public class {PolicyName}Tests
{
[TestMethod]
[DataRow(
"""
[Document]
public class PolicyDocument : IDocument
{
public void Inbound(IInboundContext context) {
context.{MethodName}(new {PolicyName}Config()
{
// required properties only
});
}
}
""",
"""
<policies>
<inbound>
<{xml-element-name} {attributes} />
</inbound>
</policies>
""",
DisplayName = "Should compile {policy-name} policy"
)]
// ... more [DataRow] entries for each test case
public void ShouldCompile{PolicyName}Policy(string code, string expectedXml)
{
code.CompileDocument().Should().BeSuccessful().And.DocumentEquivalentTo(expectedXml);
}
}
Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling (not the test namespace — this matches the existing convention){PolicyName}TestsShouldCompile{PolicyName}Policy[TestClass], [TestMethod], [DataRow])code.CompileDocument().Should().BeSuccessful().And.DocumentEquivalentTo(expectedXml)[DataRow] attribute on a single test method, with a DisplayName"""...""") for readabilityusing statements — CompilerTestInitialize.CompileDocument() wraps them automatically (adds using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring; and using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring.Expressions;)Each of the following must be a separate [DataRow]:
The baseline test — all required properties set, no optional properties:
[DataRow(
"""
[Document]
public class PolicyDocument : IDocument
{
public void Inbound(IInboundContext context) {
context.RateLimit(new RateLimitConfig()
{
Calls = 100,
RenewalPeriod = 10
});
}
}
""",
"""
<policies>
<inbound>
<rate-limit calls="100" renewal-period="10" />
</inbound>
</policies>
""",
DisplayName = "Should compile rate limit policy"
)]
One [DataRow] per optional field, added on top of required fields:
DisplayName = "Should compile rate limit policy with retry after header name"
For every property marked with [ExpressionAllowed], add a test using the expression pattern:
[DataRow(
"""
[Document]
public class PolicyDocument : IDocument
{
public void Inbound(IInboundContext context) {
context.RateLimitByKey(new RateLimitByKeyConfig()
{
Calls = CallsExp(context.ExpressionContext),
RenewalPeriod = RenewalPeriodExp(context.ExpressionContext),
CounterKey = CounterKeyExp(context.ExpressionContext)
});
}
int CallsExp(IExpressionContext context) => 100;
int RenewalPeriodExp(IExpressionContext context) => 10;
string CounterKeyExp(IExpressionContext context) => context.Product.Name;
}
""",
"""
<policies>
<inbound>
<rate-limit-by-key calls="@(100)" renewal-period="@(10)" counter-key="@(context.Product.Name)" />
</inbound>
</policies>
""",
DisplayName = "Should compile rate limit by key policy with expressions"
)]
Expression pattern rules:
{PropertyName}Exp (e.g., CallsExp, CounterKeyExp). Method must take IExpressionContext and return the appropriate type.PropertyName = MethodName(context.ExpressionContext) in the config initializer.@(...).PolicyDocument class.If the policy has child element arrays:
DisplayName = "Should compile rate limit policy with apis"
DisplayName = "Should compile rate limit policy with operations in api"
If the policy is available in multiple sections (e.g., inbound, outbound, backend), add one test per section:
"""
[Document]
public class PolicyDocument : IDocument
{
public void Outbound(IOutboundContext context) {
context.{MethodName}(new {PolicyName}Config() { /* ... */ });
}
}
""",
"""
<policies>
<outbound>
<{xml-element-name} {attributes} />
</outbound>
</policies>
""",
DisplayName = "Should compile {policy-name} policy in outbound section"
Repeat for each additional section (backend, on-error, etc.).
When interactions between optional fields matter, add a combined test.
Error case testing patterns are not yet fully defined. For now:
[Ignore] attribute and document why they are skipped:[DataRow(
"""
[Document]
public class PolicyDocument : IDocument
{
public void Inbound(IInboundContext context) {
context.RateLimit(new RateLimitConfig()
{
RenewalPeriod = 60
// Missing 'Calls' — required
});
}
}
""",
null, // No valid XML expected; compilation produces diagnostic errors
DisplayName = "Should report error when required 'Calls' field is missing"
)]
[Ignore("Error case testing patterns not yet defined. Awaiting framework guidance.")]
When error case patterns are formalized, these tests will be re-enabled and assertion logic will be added to validate diagnostic errors.
Future reference (when enabled):
expectedXml is null, the test expects compilation to fail with diagnostic errors.DisplayName values like "Should report error when {field} is missing" or "Should report error when {value} exceeds maximum."Tests rely on shared infrastructure that you do not need to modify:
CompilerTestInitialize (test/Test.Core/CompilerTestInitialize.cs) — Assembly-level setup that creates the Roslyn compilation environment and DocumentCompiler instance. Provides the CompileDocument() extension method.CompilationResultAssertion (test/Test.Core/Assertions/CompilationResultAssertion.cs) — FluentAssertions extensions for BeSuccessful() and DocumentEquivalentTo().Usings.cs (test/Test.Core/Usings.cs) — Global usings for FluentAssertions, Microsoft.VisualStudio.TestTools.UnitTesting, and assertion helpers.tools
Conventions and patterns for creating gateway emulator policy handlers in the Azure API Management policy toolkit. Use this skill when creating or modifying handler classes in src/Testing/Emulator/Policies/.
tools
Conventions and patterns for writing gateway emulator policy handler tests in the Azure API Management policy toolkit. Use this skill when creating or modifying test files in test/Test.Testing/Emulator/Policies/.
tools
Conventions and patterns for creating policy compilers in the Azure API Management policy toolkit. Use this skill when creating or modifying compiler classes in src/Core/Compiling/Policy/.
tools
Reference guide for the Azure API Management policy toolkit codebase structure. Use this skill when you need to find existing policies, infrastructure, or naming conventions.