mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
680292e04c
* Make dotnet-test analysis skills and auditor agent polyglot Five test analysis skills and the test-quality-auditor agent in plugins/dotnet-test previously activated only on .NET MSTest/xUnit/NUnit/ TUnit cues, even though the underlying techniques (assertion diversity, anti-pattern detection, pseudo-mutation gap analysis, academic smell catalog, trait tagging) apply equally to other test frameworks. This change makes them polyglot across .NET, Python (pytest/unittest), TypeScript/JavaScript (Jest/Vitest/Mocha/node:test), Java (JUnit/TestNG), Go, Ruby (RSpec/Minitest), Rust, Swift (XCTest/Swift Testing), Kotlin (JUnit/Kotest), PowerShell (Pester), and C++ (GoogleTest/Catch2/doctest). Changes ------- * New reference skill `test-analysis-extensions` with per-language extension files (dotnet, python, typescript, java, go, ruby, rust, swift, kotlin, powershell, cpp). Each documents test markers, assertion APIs, sleep / time / random APIs, skip annotations, setup/teardown, mystery-guest indicators, integration markers, and tag-support capability for the corresponding framework. * `assertion-quality`, `test-anti-patterns`, `test-gap-analysis`, `test-smell-detection`, `test-tagging` SKILL.md updated: frontmatter now lists all polyglot frameworks (keeping .NET trigger words for backward compat); bodies reference `test-analysis-extensions` and add per-language calibration (e.g., Go/Rust table-driven loops are idiomatic and not Conditional Test Logic; pytest bare `assert` is canonical; missing-await on async assertions is a new Critical smell). * `test-quality-auditor` agent now runs language detection, gates .NET-only pipeline steps (coverage-analysis, CRAP, detect-static- dependencies, testability migration, experimental dotnet skills), and recommends native tooling for non-.NET projects via an explicit Capability Matrix. * README updated to split sections by polyglot vs .NET-only. * New polyglot eval scenarios added (Python/pytest, TS/Jest, Java/JUnit) alongside existing C# scenarios in `test-anti-patterns`, `assertion-quality`, `test-smell-detection`. The .NET-only skills (writing-mstest-tests, migrate-*, coverage-analysis, crap-score, detect-static-dependencies, run-tests, filter-syntax, platform-detection, dotnet-test-frameworks, mtp-hot-reload, exp-*) are unchanged and continue to activate only for .NET work. Validated with skill-validator `check --plugin ./plugins/dotnet-test`. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR #707 review feedback * typescript.md: replace xpect.fail() recommendation (Jest has no such API) with hrow new Error(...) / explicit failing assertion. * test-tagging SKILL.md description: clarify that unittest has no canonical tag syntax (pytest markers are the auto-edit mechanism; unittest is report-only). Switch doctest reference to "decorators" rather than implying a Catch2-style [tags] mechanism exists. * test-tagging SKILL.md auto-edit list and table: use `* doctest::test_suite("tag")` decorator chain syntax for doctest in both the bullet list and the per-framework table, matching the example already shown. * cpp.md extension: spell out the Catch2 vs doctest tagging distinction in the capability matrix (Catch2 [tag], doctest * doctest::test_suite("tag") decorator). Validated with `dotnet run --project eng/skill-validator/src -- check --plugin ./plugins/dotnet-test` (23 skills + 11 agents). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
191 lines
10 KiB
YAML
191 lines
10 KiB
YAML
scenarios:
|
|
# ==========================================================================
|
|
# Scenario 1: Multiple test smells in a single test suite
|
|
# ==========================================================================
|
|
|
|
- name: "Detect multiple test smells in order processing test suite"
|
|
prompt: |
|
|
I'm worried about the quality of our OrderProcessor test suite.
|
|
Please run a full testsmells.org 19-smell catalog audit on this
|
|
suite and name each finding using the academic taxonomy
|
|
(Conditional Test Logic, Mystery Guest, Sleepy Test,
|
|
Assertion-Free Test, etc.) so I can cite the research catalog
|
|
when I share the results.
|
|
setup:
|
|
files:
|
|
- path: "OrderService.Tests/OrderService.Tests.csproj"
|
|
source: "fixtures/smelly-tests/OrderService.Tests/OrderService.Tests.csproj"
|
|
- path: "OrderService.Tests/OrderProcessorTests.cs"
|
|
source: "fixtures/smelly-tests/OrderService.Tests/OrderProcessorTests.cs"
|
|
assertions:
|
|
- type: "output_matches"
|
|
pattern: "(conditional|if.else|control flow|branch)"
|
|
- type: "output_matches"
|
|
pattern: "(no assert|assertion.free|without.*assert|zero assert|missing.*assert)"
|
|
- type: "output_matches"
|
|
pattern: "(Thread\\.Sleep|sleep|delay|sleepy)"
|
|
- type: "exit_success"
|
|
rubric:
|
|
- "Identified the conditional test logic in ProcessOrder_SetsCorrectStatus — the if/else means one branch is always untested"
|
|
- "Flagged ProcessOrder_CompletesWithoutError as having no assertions — it only calls the method without verifying anything"
|
|
- "Identified the Thread.Sleep(2000) in ProcessOrder_AsyncNotification_IsSent as a flakiness risk"
|
|
- "Noted the try/catch pattern in ProcessOrder_EmptyOrder_ThrowsValidationError and suggested using Assert.ThrowsException instead"
|
|
- "Identified the ToString() comparison in GetOrderSummary_ReturnsFormattedString as fragile"
|
|
- "Noted the File.ReadAllText with a hard-coded path in ImportOrders_FromCsv_ParsesCorrectly as an external dependency problem"
|
|
- "Provided concrete fix suggestions showing how to rewrite at least some of the smelly tests"
|
|
timeout: 120
|
|
|
|
# ==========================================================================
|
|
# Scenario 2: Clean test suite — acknowledge good quality
|
|
# ==========================================================================
|
|
|
|
- name: "Recognize well-written tests with no significant smells"
|
|
prompt: |
|
|
Can you do a research-backed academic test-smell taxonomy review
|
|
of my Calculator tests using the full testsmells.org 19-smell
|
|
catalog? I want each finding (or "no smell detected") to map to
|
|
a named smell from the academic literature so we can use these
|
|
tests as a clean reference template.
|
|
setup:
|
|
files:
|
|
- path: "Calculator.Tests/Calculator.Tests.csproj"
|
|
source: "fixtures/clean-tests/Calculator.Tests/Calculator.Tests.csproj"
|
|
- path: "Calculator.Tests/ScientificCalculatorTests.cs"
|
|
source: "fixtures/clean-tests/Calculator.Tests/ScientificCalculatorTests.cs"
|
|
assertions:
|
|
- type: "output_matches"
|
|
pattern: "(clean|good|well.written|no.*(major|significant).*(smell|issue|problem)|solid|well.structured)"
|
|
- type: "exit_success"
|
|
rubric:
|
|
- "Recognized that the test suite is well-structured with clear Arrange-Act-Assert patterns"
|
|
- "Acknowledged proper use of Assert.ThrowsException for exception testing instead of try/catch"
|
|
- "Noted the use of parameterized tests with [DataTestMethod] as a good practice"
|
|
- "Did not invent false problems or flag correct patterns as smells"
|
|
- "If any minor suggestions were made, they were presented as optional improvements rather than problems"
|
|
timeout: 120
|
|
|
|
# ==========================================================================
|
|
# Scenario 3: Integration tests — don't over-flag legitimate patterns
|
|
# ==========================================================================
|
|
|
|
- name: "Recognize integration tests and avoid false positives for external resources"
|
|
prompt: |
|
|
Our team has been arguing about whether our integration tests are
|
|
well-designed. Please use the academic testsmells.org 19-smell
|
|
catalog to give us an objective severity-ranked assessment, with
|
|
each finding tagged by its formal taxonomy name and integration-
|
|
test calibration rules applied.
|
|
setup:
|
|
files:
|
|
- path: "DataAccess.IntegrationTests/DataAccess.IntegrationTests.csproj"
|
|
source: "fixtures/integration-tests/DataAccess.IntegrationTests/DataAccess.IntegrationTests.csproj"
|
|
- path: "DataAccess.IntegrationTests/UserRepositoryIntegrationTests.cs"
|
|
source: "fixtures/integration-tests/DataAccess.IntegrationTests/UserRepositoryIntegrationTests.cs"
|
|
assertions:
|
|
- type: "output_matches"
|
|
pattern: "(integration|appropriate|expected|legitimate|acceptable)"
|
|
- type: "output_matches"
|
|
pattern: "(Sleep|delay|sleepy|conditional|if.else|assert|no assert)"
|
|
- type: "exit_success"
|
|
rubric:
|
|
- "Recognized that these are integration tests and did not flag database usage or insert-then-query patterns as smells"
|
|
- "Identified the Thread.Sleep(3000) in NotifyOnInsert_SendsEventAfterDelay as a real smell even in an integration test context"
|
|
- "Flagged the if/else conditional logic in GetUser_ReturnsCorrectType as a test smell — one branch is untested"
|
|
- "Identified BulkInsert_RunsWithoutErrors as having no assertions — it exercises code but verifies nothing"
|
|
- "Distinguished between the legitimate integration patterns (setup/teardown, multi-step persistence) and the actual smells (sleep, conditional, assertion-free)"
|
|
timeout: 120
|
|
|
|
# ==========================================================================
|
|
# Scenario 4: Non-activation — user wants to write new tests
|
|
# ==========================================================================
|
|
|
|
- name: "Decline request to write new tests from scratch"
|
|
prompt: |
|
|
I need to write unit tests for my ShoppingCart class. It supports
|
|
adding items, removing items, calculating totals, and applying
|
|
coupon codes. Can you write a complete MSTest test suite for me?
|
|
expect_activation: false
|
|
setup:
|
|
files:
|
|
- path: "ShoppingCart.cs"
|
|
content: |
|
|
namespace Store;
|
|
|
|
public sealed class ShoppingCart
|
|
{
|
|
public void AddItem(string sku, int quantity, decimal price) => throw new NotImplementedException();
|
|
public void RemoveItem(string sku) => throw new NotImplementedException();
|
|
public decimal CalculateTotal() => throw new NotImplementedException();
|
|
public void ApplyCoupon(string code) => throw new NotImplementedException();
|
|
}
|
|
assertions:
|
|
- type: "output_matches"
|
|
pattern: "(TestMethod|TestClass|\\[Fact\\]|test)"
|
|
rubric:
|
|
- "Wrote test methods for the ShoppingCart class"
|
|
- "Covered multiple methods of the class"
|
|
timeout: 300
|
|
|
|
# ==========================================================================
|
|
# Scenario: Polyglot — canonical smells in a JUnit/Java suite
|
|
# ==========================================================================
|
|
|
|
- name: "Polyglot: detect canonical test smells in a JUnit/Java Catalog suite"
|
|
prompt: |
|
|
Audit `src/test/java/com/example/CatalogTest.java` for test smells.
|
|
The production code is at `src/main/java/com/example/Catalog.java`.
|
|
|
|
This is JUnit 5 / Java, not .NET — apply the same smell catalog
|
|
using JUnit equivalents (`@Test`, `@BeforeEach`, `@Disabled`,
|
|
`Thread.sleep`, `assertThrows`, etc.).
|
|
|
|
Walk through each test method by name and identify which canonical
|
|
smell it exhibits. Recommend a concrete refactor for each. Do not
|
|
edit the files — read-only review.
|
|
setup:
|
|
files:
|
|
- path: "pom.xml"
|
|
source: "fixtures/junit-smells/pom.xml"
|
|
- path: "src/main/java/com/example/Catalog.java"
|
|
source: "fixtures/junit-smells/src/main/java/com/example/Catalog.java"
|
|
- path: "src/test/java/com/example/CatalogTest.java"
|
|
source: "fixtures/junit-smells/src/test/java/com/example/CatalogTest.java"
|
|
assertions:
|
|
- type: "output_matches"
|
|
pattern: "(conditional|if/else|branch|loop with if)"
|
|
- type: "output_matches"
|
|
pattern: "(mystery guest|file|external|temp)"
|
|
- type: "output_matches"
|
|
pattern: "(sleep|Thread\\.sleep|sleepy|wall.clock)"
|
|
- type: "output_matches"
|
|
pattern: "(no assertion|assertion.?free|empty test|missing assert)"
|
|
- type: "output_matches"
|
|
pattern: "(eager|multiple.*method|too many|doing too much)"
|
|
- type: "output_matches"
|
|
pattern: "(magic|literal|unexplain|42|hard.?coded)"
|
|
- type: "output_matches"
|
|
pattern: "(sensitiv|toString|format.*equal)"
|
|
- type: "output_matches"
|
|
pattern: "(try.catch|exception handling|manual.*catch|assertThrows)"
|
|
- type: "output_matches"
|
|
pattern: "(general fixture|unused|rng|over.*setup)"
|
|
- type: "output_matches"
|
|
pattern: "(disabled|ignored|@Disabled|skipped)"
|
|
- type: "exit_success"
|
|
rubric:
|
|
- "Identified JUnit-specific patterns correctly (did NOT mention MSTest/xUnit attributes as if present)"
|
|
- "Mapped addConditionalLogic → Conditional Test Logic (branching inside test)"
|
|
- "Mapped addLoadsFromFile → Mystery Guest (reads from the file system)"
|
|
- "Mapped addSleepy → Sleepy Test (Thread.sleep used for synchronization)"
|
|
- "Mapped addAndDoNothing → Assertion-Free Test"
|
|
- "Mapped doEverythingAtOnce → Eager Test (exercises many methods in one test)"
|
|
- "Mapped quantityAfterAdds → Magic Number Test (unexplained 41, 1, 42)"
|
|
- "Mapped toStringFormat → Sensitive Equality (asserts on toString() output)"
|
|
- "Mapped addNullSkuManualCatch → Exception Handling in Tests (recommended assertThrows)"
|
|
- "Mapped quantityZeroOnUnknownSku → General Fixture (rng is set up in @BeforeEach but never used)"
|
|
- "Mapped disabledTest → Ignored / Disabled Test (@Disabled with vague reason)"
|
|
- "Acknowledged addThrowsOnNegativeCount as a well-written test that uses assertThrows correctly"
|
|
reject_tools: ["bash", "edit", "create"]
|
|
timeout: 180
|
|
|