mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
0f31228b58
* Fix evaluation timeouts and improve prompts for dotnet-test skills
- writing-mstest-tests: increase global vally timeout from 3m to 5m to match
the 300s eval.yaml timeout for the complex 'Modernize legacy test patterns' stimulus
- code-testing-agent: increase timeout from 40m/2400s to 60m/3600s
- mtp-hot-reload: increase timeout from 6m to 10m and remove overly strict
expect_tools constraint on launchSettings stimulus
- migrate-mstest-v1v2-to-v3: rephrase prompt for assertion overload errors to
mention CS1501 and cover AreNotEqual/AreSame alongside AreEqual
* Increase eval timeouts for mtp-hot-reload and migrate-mstest-v1v2-to-v3 scenarios
* Strengthen activation prompts and add missing vally scenarios
- migrate-mstest-v1v2-to-v3: Add explicit 'MSTest v2 to v3' migration
language in .testsettings and DataRow prompts (both eval.yaml and
eval.vally.yaml)
- writing-mstest-tests: Add 'MSTest' keyword and skill-specific
terminology to all prompts that lacked activation signal
- writing-mstest-tests: Add 5 missing vally scenarios (string
assertions, comparison assertions, collection/null/reference
assertions, conditional execution, parallelization)
- Add service-registry fixture files for the collection assertions
scenario
* Improve skill activation via SKILL.md descriptions and prompt alignment
Three-pronged fix for systematic NOT ACTIVATED failures:
1. SKILL.md descriptions: Restructure writing-mstest-tests, migrate-
mstest-v1v2-to-v3, and code-testing-agent descriptions to use the
proven 'Use when user says' pattern with quoted trigger phrases
(matching the working run-tests pattern)
2. Vally prompts: Each prompt now contains at least one exact quoted
trigger phrase from its SKILL.md description to ensure strong
description-to-prompt matching
3. Specific fixes:
- writing-mstest-tests: All 15 prompts now include MSTest-specific
trigger phrases (Assert.ThrowsExactly, sealed test class, DataRow,
DynamicData, Assert.HasCount, Assert.IsInstanceOfType, etc.)
- migrate-mstest-v1v2-to-v3: Add '.NET 5 dropped' and 'framework
compatibility issues' to trigger phrases; strengthen dropped-TFM
prompt
- code-testing-agent: Add 'generate comprehensive unit tests' and
'achieve high code coverage' to trigger phrases
* Revert SKILL.md description changes that caused activation regression
The description restructuring in 67056d8ec broke skill activation:
- migrate-mstest-v1v2-to-v3: went from 6/9 activating to 0/9
- writing-mstest-tests: lost isolated activation
- code-testing-agent: unnecessary change to working description
Restore all three SKILL.md files to their pre-regression state.
Keep the vally prompt improvements from 259727e.
* Fix writing-mstest-tests plugin-mode activation
- Add MSTest carve-out to code-testing-agent DO NOT USE FOR to prevent
it from intercepting MSTest-specific prompts
- Add test parallelization/MSTest.Sdk keywords to writing-mstest-tests
description (scenario 15 failed even in isolated mode)
- Strengthen prompts to be more MSTest-specific:
- Scenario 1: emphasize MSTest patterns over generic 'write tests'
- Scenario 4: remove vague 'something seems off', directly ask to
fix swapped Assert.AreEqual arguments
- Scenario 5: reframe as modernization request with specific APIs
- Scenario 13: name specific MSTest assertion APIs in the prompt
* Fix writing-mstest-tests description over 1024 char limit
Shorten the USE FOR section by removing redundant 'help me write
comprehensive tests' and condensing the assertion API list.
Description is now 944 chars (limit: 1024).
* Increase vally job timeout from 60m to 180m
The code-testing-agent eval has a 60m per-stimulus timeout, and vally
runs multiple configurations (baseline, isolated, plugin). The 60m
job-level timeout was causing the job to be cancelled mid-evaluation.
Match the 180m timeout from the evaluate job in evaluation.yml.
* Address PR review comments
- Add IsPackable=false to writing-mstest-tests fixture csproj for
consistency with other dotnet-test fixture projects
- Fix grammar in migrate-mstest-v1v2-to-v3 eval prompts: add comma
after 'upgrade' and add 'file' for clarity (both eval.yaml and
eval.vally.yaml)
* Trim dotnet-test aggregate description size under 15,000 limit
Consolidate duplicate filter keyword mentions in migrate-vstest-to-mtp
and shorten the cross-reference in migrate-xunit-to-xunit-v3 while
keeping the --filter-class/--filter-trait/--filter-query trigger
keywords for skill activation.
* Fix vally skill activation for 9 failing eval scenarios
Improve eval.vally.yaml prompts that were too specific, causing the model
to answer from general knowledge without activating the skill:
- migrate-mstest-v1v2-to-v3: Remove leading question that gives away the
answer ('Is .NET 5 dropped?'); use multi-target fixture matching eval.yaml
- writing-mstest-tests (7 scenarios): Add 'following MSTest best practices'
to trigger skill reading; make prompts more open-ended (don't name exact
APIs like OSCondition, Assert.AreSame); match eval.yaml prompt style
- code-testing-agent: Clarify app complexity to encourage skill pipeline
The pattern: vally prompts that give away exact API names or answers let
the model skip reading the skill. More open-ended prompts referencing
'best practices' trigger skill activation.
* Improve skills and eval prompts for regression scenarios
migrate-xunit-to-xunit-v3 SKILL.md:
- Restructure from 16 steps to 13, merging redundant steps
- Move test platform selection from step 12 to step 4
- Mark steps 6-12 as conditional with prioritization note
- Remove external URL references that caused web_fetch detours
writing-mstest-tests SKILL.md:
- Add Response Guidelines for proportional responses
- Remove redundant Validation checklist and Common Pitfalls table
(all items already covered in workflow steps)
- Reduces token count from 3,305 to 2,944
migrate-mstest-v1v2-to-v3 eval.vally.yaml:
- Relax DataRow rubric to account for MSTest 3.8.0 fixing the
16-parameter constructor limit
writing-mstest-tests eval.vally.yaml:
- Make 3 prompts more open-ended by removing API name hints
(Assert.HasCount, Assert.StartsWith, DynamicData to ValueTuples)
so baseline model cannot answer confidently without the skill
530 lines
24 KiB
YAML
530 lines
24 KiB
YAML
scenarios:
|
|
# ============================================================================
|
|
# Goal 1: Writing new MSTest tests from scratch
|
|
# ============================================================================
|
|
|
|
- name: "Write unit tests for a service class"
|
|
prompt: "I need to write MSTest unit tests for my OrderService class following MSTest best practices. Help me write comprehensive tests with sealed test classes and Assert.ThrowsExactly."
|
|
setup:
|
|
copy_test_files: true
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "\\[TestClass\\]"
|
|
- type: output_matches
|
|
pattern: "\\[TestMethod\\]"
|
|
- type: output_matches
|
|
pattern: "\\bsealed\\b"
|
|
- type: output_matches
|
|
pattern: "Assert\\.ThrowsExactly|Assert\\.Throws"
|
|
rubric:
|
|
- "Uses [TestClass] and [TestMethod] attributes correctly"
|
|
- "Seals the test class with the 'sealed' keyword"
|
|
- "Follows Arrange-Act-Assert (AAA) pattern with comments or clear structure"
|
|
- "Names tests descriptively using MethodName_Scenario_ExpectedBehavior or similar convention"
|
|
- "Tests both success and failure paths (e.g., null input, empty items)"
|
|
- "Uses Assert.ThrowsExactly or Assert.Throws for exception testing instead of [ExpectedException]"
|
|
- "Uses Assert.AreEqual with expected as first argument and actual as second"
|
|
timeout: 180
|
|
|
|
- name: "Write data-driven tests for a calculator"
|
|
prompt: "I have a PriceCalculator class with CalculateTotal and ApplyDiscount methods. Help me write data-driven MSTest tests using DataRow and DynamicData that cover multiple input combinations following modern MSTest best practices."
|
|
setup:
|
|
copy_test_files: true
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "\\[DataRow\\]|\\[DynamicData\\]"
|
|
- type: output_matches
|
|
pattern: "\\bsealed\\b"
|
|
- type: output_matches
|
|
pattern: "Assert\\.ThrowsExactly|Assert\\.Throws"
|
|
rubric:
|
|
- "Uses [DataRow] for simple inline test data or [DynamicData] for complex data"
|
|
- "If using DynamicData, prefers ValueTuple return type over IEnumerable<object[]>"
|
|
- "Covers edge cases like zero values, boundary conditions, and invalid inputs"
|
|
- "Seals the test class"
|
|
- "Uses Assert.ThrowsExactly or Assert.Throws for testing invalid argument scenarios"
|
|
- "Does not use manual foreach loops to iterate test data — uses proper data-driven attributes instead"
|
|
timeout: 180
|
|
|
|
- name: "Write async tests with cancellation"
|
|
prompt: |
|
|
I have this async service that I need to test:
|
|
|
|
```csharp
|
|
public sealed class DataFetcher
|
|
{
|
|
private readonly HttpClient _client;
|
|
public DataFetcher(HttpClient client) => _client = client;
|
|
|
|
public async Task<string> FetchAsync(string url, CancellationToken cancellationToken = default)
|
|
{
|
|
var response = await _client.GetAsync(url, cancellationToken);
|
|
response.EnsureSuccessStatusCode();
|
|
return await response.Content.ReadAsStringAsync(cancellationToken);
|
|
}
|
|
}
|
|
```
|
|
|
|
How should I write MSTest tests for this using modern MSTest patterns for async testing, timeouts, and cancellation token handling?
|
|
setup:
|
|
copy_test_files: true
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "async Task"
|
|
- type: output_matches
|
|
pattern: "\\[Timeout\\]"
|
|
- type: output_matches
|
|
pattern: "CancellationToken"
|
|
rubric:
|
|
- "Uses async Task test methods (not async void)"
|
|
- "Uses TestContext.CancellationToken or mentions its importance for cooperative timeout"
|
|
- "Uses [Timeout] attribute for tests that could hang"
|
|
- "Uses Assert.ThrowsExactlyAsync or Assert.ThrowsAsync for async exception testing"
|
|
- "Does not use CancellationToken.None when TestContext.CancellationToken is available"
|
|
- "Seals the test class"
|
|
timeout: 120
|
|
|
|
# ============================================================================
|
|
# Goal 2: Fixing anti-patterns in existing tests
|
|
# ============================================================================
|
|
|
|
- name: "Fix swapped Assert.AreEqual arguments"
|
|
prompt: |
|
|
Something seems off with my tests — I think I need to fix swapped Assert.AreEqual arguments. Can you review and fix the MSTest assertions?
|
|
|
|
```csharp
|
|
[TestClass]
|
|
public class MathTests
|
|
{
|
|
[TestMethod]
|
|
public void Add_TwoNumbers_ReturnsSum()
|
|
{
|
|
var result = Calculator.Add(2, 3);
|
|
Assert.AreEqual(result, 5);
|
|
}
|
|
|
|
[TestMethod]
|
|
public void Multiply_ByZero_ReturnsZero()
|
|
{
|
|
var result = Calculator.Multiply(42, 0);
|
|
Assert.AreEqual(result, 0);
|
|
}
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "Assert\\.AreEqual\\(5"
|
|
- type: output_matches
|
|
pattern: "Assert\\.AreEqual\\(0"
|
|
rubric:
|
|
- "Identifies the swapped arguments in Assert.AreEqual — expected should be first, actual second"
|
|
- "Fixes to Assert.AreEqual(5, result) and Assert.AreEqual(0, result)"
|
|
- "Explains why argument order matters (failure messages show 'Expected: X, Actual: Y')"
|
|
timeout: 120
|
|
|
|
- name: "Modernize legacy test patterns"
|
|
prompt: "Can you review these MSTest tests and modernize them to use current MSTest best practices like sealed classes and Assert.ThrowsExactly?"
|
|
setup:
|
|
files:
|
|
- path: "TestProject.csproj"
|
|
source: "fixtures/legacy-antipatterns/TestProject.csproj"
|
|
- path: "PriceCalculatorTests.cs"
|
|
source: "fixtures/legacy-antipatterns/PriceCalculatorTests.cs"
|
|
- path: "PriceCalculator.cs"
|
|
source: "fixtures/legacy-antipatterns/PriceCalculator.cs"
|
|
commands:
|
|
- "dotnet restore"
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "\\bsealed\\b"
|
|
- type: output_matches
|
|
pattern: "Assert\\.ThrowsExactly|Assert\\.Throws"
|
|
- type: output_matches
|
|
pattern: "IsInstanceOfType"
|
|
rubric:
|
|
- "Seals the test class (adds 'sealed' keyword)"
|
|
- "Replaces [ExpectedException] with Assert.ThrowsExactly or Assert.Throws"
|
|
- "Fixes the swapped Assert.AreEqual arguments (expected first, actual second)"
|
|
- "Moves synchronous setup from [TestInitialize] into the constructor, enabling readonly fields and satisfying nullability analyzers"
|
|
- "Removes nullable annotation from TestContext property or switches to constructor injection"
|
|
- "Improves test naming to be descriptive (replaces 'Test1', 'TestNegativeQuantity')"
|
|
- "Replaces hard cast with Assert.IsInstanceOfType"
|
|
- "Replaces manual foreach test data loop with [DataRow] or [DynamicData] attributes"
|
|
timeout: 300
|
|
|
|
- name: "Replace ExpectedException with Assert.Throws"
|
|
prompt: |
|
|
I have this MSTest test that uses [ExpectedException]. How should I modernize it to use Assert.ThrowsExactly instead?
|
|
|
|
```csharp
|
|
[TestMethod]
|
|
[ExpectedException(typeof(ArgumentNullException))]
|
|
public void CreateUser_NullEmail_ThrowsException()
|
|
{
|
|
var service = new UserService();
|
|
service.CreateUser(null, "John");
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "Assert\\.ThrowsExactly|Assert\\.Throws"
|
|
rubric:
|
|
- "The modernized test removes the ExpectedException attribute and wraps the throwing call in an inline assertion using Assert.ThrowsExactly or Assert.Throws"
|
|
- "Shows how to capture the thrown exception to verify its properties such as message or parameter name"
|
|
- "Explains when to prefer ThrowsExactly (exact type match) versus Throws (matches derived types too)"
|
|
timeout: 120
|
|
|
|
# ============================================================================
|
|
# Goal 3: Using correct assertion methods
|
|
# ============================================================================
|
|
|
|
- name: "Use proper collection assertions"
|
|
prompt: |
|
|
I'm writing MSTest tests for a method that returns a list. What MSTest collection assertions should I use instead of Assert.IsTrue? Here's what I have:
|
|
|
|
```csharp
|
|
[TestMethod]
|
|
public void GetActiveUsers_ReturnsOnlyActiveUsers()
|
|
{
|
|
var service = new UserService();
|
|
var users = service.GetActiveUsers();
|
|
|
|
Assert.IsTrue(users.Count > 0);
|
|
Assert.IsTrue(users.All(u => u.IsActive));
|
|
Assert.IsTrue(users.Count() == 3);
|
|
var admin = users.Single(u => u.Role == "Admin");
|
|
Assert.IsTrue(admin != null);
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "Assert\\.HasCount|Assert\\.AreEqual\\(3"
|
|
- type: output_matches
|
|
pattern: "ContainsSingle|Assert\\.IsNotNull"
|
|
rubric:
|
|
- "The non-empty validation no longer relies on a generic Assert.IsTrue boolean check — it uses a dedicated assertion that clearly reports 'collection was empty' on failure"
|
|
- "The exact-count validation uses a count-specific or equality assertion rather than wrapping the comparison in Assert.IsTrue"
|
|
- "The single-element lookup uses an assertion that produces a meaningful failure message when zero or multiple elements match, rather than throwing an unrelated exception"
|
|
- "The null check uses a null-specific assertion rather than Assert.IsTrue with a boolean null comparison"
|
|
- "Explains why specialized assertions produce better failure diagnostics than generic Assert.IsTrue"
|
|
timeout: 120
|
|
|
|
- name: "Use proper type assertions instead of casts"
|
|
prompt: |
|
|
I'm writing MSTest tests for a factory method. Is there a better MSTest assertion to check the returned type instead of hard casting?
|
|
|
|
```csharp
|
|
[TestMethod]
|
|
public void Create_ReturnsCorrectHandler()
|
|
{
|
|
var factory = new HandlerFactory();
|
|
var result = factory.Create("email");
|
|
|
|
var handler = (EmailHandler)result;
|
|
Assert.IsNotNull(handler);
|
|
Assert.AreEqual("email", handler.Type);
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "IsInstanceOfType"
|
|
rubric:
|
|
- "Replaces the hard cast with a type-checking assertion that produces a clear failure message showing the actual type when the type does not match"
|
|
- "Shows how to access the strongly-typed result after the type check so further property assertions can be made without a separate cast"
|
|
- "Explains the diagnostic benefit — a type assertion failure message shows expected vs actual type, while a hard cast just throws InvalidCastException"
|
|
- "Covers both MSTest 3.x and 4.x syntax variants for type assertions (out parameter vs direct return)"
|
|
timeout: 120
|
|
|
|
# ============================================================================
|
|
# Goal 4: Test lifecycle and setup
|
|
# ============================================================================
|
|
|
|
- name: "Set up test lifecycle correctly"
|
|
prompt: |
|
|
I need to set up my MSTest test class with both synchronous and asynchronous initialization using constructor injection for TestContext. What's the recommended way to do this in modern MSTest?
|
|
setup:
|
|
files:
|
|
- path: "TestProject.csproj"
|
|
source: "fixtures/modern-mstest/TestProject.csproj"
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "constructor|\\bctor\\b"
|
|
- type: output_matches
|
|
pattern: "TestContext"
|
|
- type: output_matches
|
|
pattern: "\\[TestInitialize\\]|TestInitialize"
|
|
rubric:
|
|
- "Always initializes in the constructor — enables readonly fields and satisfies nullability analyzers (fields guaranteed non-null after construction)"
|
|
- "Uses [TestInitialize] only for async initialization, combined with constructor for sync parts"
|
|
- "Injects TestContext via constructor parameter (MSTest 3.6+) rather than property"
|
|
- "Mentions the execution order: Constructor → TestContext property → [TestInitialize] → Test → [TestCleanup] → Dispose"
|
|
- "Seals the test class"
|
|
- "If TestContext property is used, does not add nullable annotation or = null! initializer"
|
|
timeout: 120
|
|
|
|
- name: "Use DynamicData with ValueTuples over object arrays"
|
|
prompt: |
|
|
I have this MSTest data-driven test using DynamicData with object arrays. Is there a more type-safe way to write this in modern MSTest?
|
|
|
|
```csharp
|
|
[TestMethod]
|
|
[DynamicData(nameof(TestData))]
|
|
public void Validate_ReturnsExpected(string input, bool expected)
|
|
{
|
|
var result = Validator.IsValid(input);
|
|
Assert.AreEqual(expected, result);
|
|
}
|
|
|
|
public static IEnumerable<object[]> TestData =>
|
|
[
|
|
["valid@email.com", true],
|
|
["invalid", false],
|
|
["", false],
|
|
];
|
|
```
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "ValueTuple|\\(string.*bool\\)"
|
|
- type: output_matches
|
|
pattern: "IEnumerable<\\("
|
|
rubric:
|
|
- "Recommends switching from IEnumerable<object[]> to IEnumerable<(string input, bool expected)> ValueTuples"
|
|
- "Explains that ValueTuples provide compile-time type safety"
|
|
- "Shows the correct ValueTuple syntax with named elements"
|
|
- "Mentions TestDataRow<T> as an option when custom DisplayName or metadata is needed"
|
|
|
|
# ============================================================================
|
|
# Goal 5: String assertions
|
|
# ============================================================================
|
|
|
|
- name: "Use string assertions for format validation"
|
|
prompt: |
|
|
Help me write MSTest tests for this formatting utility. I want to use the right MSTest string assertion methods like Assert.StartsWith and Assert.EndsWith to validate the output formats.
|
|
|
|
```csharp
|
|
namespace Contoso.Text;
|
|
|
|
public sealed class StringFormatter
|
|
{
|
|
public string FormatPhoneNumber(string digits)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(digits);
|
|
if (digits.Length != 10)
|
|
throw new ArgumentException("Must be exactly 10 digits.", nameof(digits));
|
|
return $"({digits[..3]}) {digits[3..6]}-{digits[6..]}";
|
|
}
|
|
|
|
public string BuildGreeting(string name, string title = "Mr.")
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(name);
|
|
return $"Dear {title} {name},";
|
|
}
|
|
|
|
public string GenerateSlug(string title)
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(title);
|
|
return Regex.Replace(title.Trim().ToLowerInvariant(), @"[^a-z0-9]+", "-").Trim('-');
|
|
}
|
|
|
|
public string FormatCurrency(decimal amount, string symbol = "$")
|
|
{
|
|
return $"{symbol}{amount:F2}";
|
|
}
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "Assert\\.(StartsWith|EndsWith|MatchesRegex)"
|
|
- type: output_matches
|
|
pattern: "\\bsealed\\b"
|
|
rubric:
|
|
- "Validates string format structure using targeted string assertions like StartsWith, EndsWith, or MatchesRegex rather than only exact equality checks"
|
|
- "Tests FormatPhoneNumber validates the parenthesized area code and hyphen structure"
|
|
- "Tests BuildGreeting validates the output starts with 'Dear' and ends with a comma"
|
|
- "Tests GenerateSlug validates the slug pattern contains only lowercase letters, digits, and hyphens"
|
|
- "Tests exception handling for null or invalid inputs"
|
|
timeout: 180
|
|
|
|
# ============================================================================
|
|
# Goal 6: Comparison assertions
|
|
# ============================================================================
|
|
|
|
- name: "Use comparison assertions for boundary testing"
|
|
prompt: |
|
|
I have a scoring system and need to write MSTest tests with proper boundary checking. What MSTest comparison assertions like Assert.IsGreaterThan or Assert.IsInRange should I use?
|
|
|
|
```csharp
|
|
namespace Contoso.Scoring;
|
|
|
|
public sealed class ScoreCalculator
|
|
{
|
|
public double CalculatePercentage(int correct, int total)
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(total);
|
|
ArgumentOutOfRangeException.ThrowIfNegative(correct);
|
|
ArgumentOutOfRangeException.ThrowIfGreaterThan(correct, total);
|
|
return (double)correct / total * 100.0;
|
|
}
|
|
|
|
public string GetGrade(double percentage) => percentage switch
|
|
{
|
|
>= 90 => "A",
|
|
>= 80 => "B",
|
|
>= 70 => "C",
|
|
>= 60 => "D",
|
|
_ => "F"
|
|
};
|
|
|
|
public double NormalizeScore(double rawScore, double maxRaw)
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfNegative(rawScore);
|
|
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(maxRaw);
|
|
return Math.Min(rawScore / maxRaw * 100.0, 100.0);
|
|
}
|
|
}
|
|
```
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "Assert\\.(IsGreaterThan|IsLessThan|IsInRange|IsGreaterThanOrEqualTo|IsLessThanOrEqualTo)"
|
|
- type: output_matches
|
|
pattern: "\\bsealed\\b"
|
|
rubric:
|
|
- "Uses comparison assertions like IsGreaterThan, IsLessThan, or IsInRange for validating numeric bounds instead of Assert.IsTrue with manual comparisons"
|
|
- "Tests that CalculatePercentage returns values in the 0-100 range for valid inputs"
|
|
- "Tests boundary conditions at grade thresholds (e.g., exactly 90 vs 89)"
|
|
- "Tests that NormalizeScore caps the result at 100 when rawScore exceeds maxRaw"
|
|
- "Seals the test class"
|
|
timeout: 120
|
|
|
|
# ============================================================================
|
|
# Goal 7: Collection, null, and reference assertions
|
|
# ============================================================================
|
|
|
|
- name: "Write tests with collection, null, and reference assertions"
|
|
prompt: "Write MSTest tests for my ServiceRegistry class using the most appropriate assertion for each check. I need tests that verify registration, resolution returning the same instance, null for unregistered services, clearing all services, and removal."
|
|
setup:
|
|
files:
|
|
- path: "src/ServiceRegistry.cs"
|
|
content: |
|
|
namespace Contoso.Services;
|
|
|
|
public sealed class ServiceRegistry
|
|
{
|
|
private readonly Dictionary<Type, object> _services = new();
|
|
|
|
public void Register<T>(T service) where T : class
|
|
{
|
|
ArgumentNullException.ThrowIfNull(service);
|
|
_services[typeof(T)] = service;
|
|
}
|
|
|
|
public T? Resolve<T>() where T : class =>
|
|
_services.TryGetValue(typeof(T), out var svc) ? (T)svc : null;
|
|
|
|
public T ResolveRequired<T>() where T : class =>
|
|
Resolve<T>() ?? throw new InvalidOperationException($"{typeof(T).Name} not registered.");
|
|
|
|
public IReadOnlyList<object> GetAll() => [.. _services.Values];
|
|
|
|
public void Remove<T>() where T : class => _services.Remove(typeof(T));
|
|
|
|
public void Clear() => _services.Clear();
|
|
}
|
|
- path: "src/Contoso.Services.csproj"
|
|
content: |
|
|
<Project Sdk="Microsoft.NET.Sdk">
|
|
<PropertyGroup>
|
|
<TargetFramework>net9.0</TargetFramework>
|
|
</PropertyGroup>
|
|
</Project>
|
|
- path: "tests/Contoso.Services.Tests.csproj"
|
|
content: |
|
|
<Project Sdk="Microsoft.NET.Sdk">
|
|
<PropertyGroup>
|
|
<TargetFramework>net9.0</TargetFramework>
|
|
</PropertyGroup>
|
|
<ItemGroup>
|
|
<PackageReference Include="MSTest" Version="3.8.2" />
|
|
</ItemGroup>
|
|
<ItemGroup>
|
|
<ProjectReference Include="../src/Contoso.Services.csproj" />
|
|
</ItemGroup>
|
|
</Project>
|
|
assertions:
|
|
- type: file_exists
|
|
path: "tests/*.cs"
|
|
- type: file_contains
|
|
path: "tests/*.cs"
|
|
value: "[TestClass]"
|
|
rubric:
|
|
- "Verifies reference identity (same object instance, not just value equality) when testing that resolving a registered service returns the exact object that was registered"
|
|
- "Checks that resolving an unregistered service type returns null, using a null-specific assertion rather than a boolean check"
|
|
- "Asserts the collection is empty after calling Clear, using a dedicated empty-collection assertion rather than checking count manually"
|
|
- "Verifies that a removed service is no longer resolvable after calling Remove (e.g., returns null or is absent from the collection)"
|
|
- "The written tests reference correct class and method names from the provided source code"
|
|
timeout: 180
|
|
|
|
# ============================================================================
|
|
# Goal 8: Advanced features — conditional execution, retry, and cleanup
|
|
# ============================================================================
|
|
|
|
- name: "Configure conditional execution, retry, and cleanup"
|
|
prompt: |
|
|
I have MSTest tests that:
|
|
1. Only work on Windows because they use the Windows registry
|
|
2. Should be skipped in CI because they require a local GPU
|
|
3. Sometimes fail due to a flaky external weather API
|
|
4. Create temporary files that need to be deleted even if the test fails
|
|
|
|
How should I handle all of these using MSTest attributes and patterns?
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "OSCondition|OsCondition"
|
|
- type: output_matches
|
|
pattern: "CICondition|CiCondition"
|
|
- type: output_matches
|
|
pattern: "Retry"
|
|
- type: output_matches
|
|
pattern: "TestCleanup|IDisposable"
|
|
rubric:
|
|
- "Uses an OS condition attribute to restrict the registry test to Windows only"
|
|
- "Uses a CICondition attribute to exclude the GPU test from CI environments"
|
|
- "Uses a retry attribute for the flaky weather API test with a small retry count"
|
|
- "Uses [TestCleanup] or IDisposable/IAsyncDisposable for deleting temporary files to ensure cleanup runs even on test failure"
|
|
- "Advises that retry should only be used for genuinely flaky external dependencies, not to mask real bugs"
|
|
timeout: 120
|
|
|
|
# ============================================================================
|
|
# Goal 9: Test parallelization and MSTest.Sdk project setup
|
|
# ============================================================================
|
|
|
|
- name: "Configure test parallelization and MSTest.Sdk project"
|
|
prompt: |
|
|
I'm setting up a new MSTest project from scratch. I want:
|
|
1. The simplest possible project file using MSTest.Sdk
|
|
2. Tests to run in parallel by default
|
|
3. But my database integration tests must run sequentially
|
|
|
|
What's the recommended MSTest setup?
|
|
reject_tools: ["bash", "edit", "create"]
|
|
assertions:
|
|
- type: output_matches
|
|
pattern: "MSTest\\.Sdk|MSTest.Sdk"
|
|
- type: output_matches
|
|
pattern: "Parallelize"
|
|
- type: output_matches
|
|
pattern: "DoNotParallelize"
|
|
rubric:
|
|
- "Recommends MSTest.Sdk for the simplest possible project file"
|
|
- "Shows assembly-level Parallelize attribute configuration with Workers and Scope"
|
|
- "Uses [DoNotParallelize] on the database integration test class to opt it out of parallel execution"
|
|
- "Suggests putting the MSTest.Sdk version in global.json so all test projects stay in sync"
|
|
timeout: 120
|