Skip to main content

policy-testing

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/.

来源信息

仓库
Azure/azure-api-management-policy-toolkit
最近来源活动
2026年3月8日 18:53
检测到的 SKILL.md 语言
英语
星标
95
分支
37

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
policy-testing
description
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/.
# Policy Testing Patterns This skill describes how to write tests for policy compilation in the Azure API Management policy toolkit. ## Test File — `test/Test.Core/Compiling/{PolicyName}Tests.cs` ### File Template ```csharp // 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); } } ``` ### Key Conventions - **Namespace**: `Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling` (not the test namespace — this matches the existing convention) - **Class name**: `{PolicyName}Tests` - **Test method name**: `ShouldCompile{PolicyName}Policy` - **Framework**: MSTest (`[TestClass]`, `[TestMethod]`, `[DataRow]`) - **Assertions**: FluentAssertions via `code.CompileDocument().Should().BeSuccessful().And.DocumentEquivalentTo(expectedXml)` - **Each test scenario** is a separate `[DataRow]` attribute on a single test method, with a `DisplayName` - **C# code strings** use raw string literals (`"""..."""`) for readability - **Test code does not need `using` statements** — `CompilerTestInitialize.CompileDocument()` wraps them automatically (adds `using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring;` and `using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring.Expressions;`) ## Required Test Coverage Each of the following must be a separate `[DataRow]`: ### 1. Required Fields Only (Constant Values) The baseline test — all required properties set, no optional properties: ```csharp [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" )] ``` ### 2. Each Optional Field Individually One `[DataRow]` per optional field, added on top of required fields: ```csharp DisplayName = "Should compile rate limit policy with retry after header name" ``` ### 3. Expression Values For every property marked with `[ExpressionAllowed]`, add a test using the expression pattern: ```csharp [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:** - **Expression method naming**: Name expression helper methods as `{PropertyName}Exp` (e.g., `CallsExp`, `CounterKeyExp`). Method must take `IExpressionContext` and return the appropriate type. - Call it as `PropertyName = MethodName(context.ExpressionContext)` in the config initializer. - The expected XML wraps the method's return expression in `@(...)`. - Expression methods are defined as members of the `PolicyDocument` class. ### 4. Child Elements If the policy has child element arrays: ```csharp DisplayName = "Should compile rate limit policy with apis" DisplayName = "Should compile rate limit policy with operations in api" ``` ### 5. Multi-Section Tests If the policy is available in multiple sections (e.g., inbound, outbound, backend), **add one test per section**: ```csharp """ [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.). ### 6. All Optional Fields Together (if combinatorially important) When interactions between optional fields matter, add a combined test. ### 7. Error Cases (Skipped for Now) Error case testing patterns are not yet fully defined. For now: - **Do NOT implement error test cases** during Phase 5. - If you add error cases, mark them with `[Ignore]` attribute and document why they are skipped: ```csharp [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):** - When `expectedXml` is `null`, the test expects compilation to fail with diagnostic errors. - Use `DisplayName` values like "Should report error when {field} is missing" or "Should report error when {value} exceeds maximum." ## Test Infrastructure 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.
在 GitHub 查看