Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
日本語の概要は準備中です。原文の説明を表示しています。
Write, run, or repair .NET tests that use NUnit. Use when a repo uses `NUnit`, `[Test]`, `[TestCase]`, `[TestFixture]`, or NUnit3TestAdapter for VSTest or Microsoft.Testing.Platform execution. USE FOR: writing or reviewing NUnit tests; using [Test], [TestCase], [TestFixture], [SetUp], [TearDown] attributes; configuring NUnit3TestAdapter or NUnit.Analyzers. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.
インストール方法を見るインストールする前に、エージェントに与えられる指示の中身を確認できます。
Keep native test progress and ANSI visible; use the detected runner's supported flags (--progress on --ansi on for MTP/TUnit), not MTP switches on VSTest. Keep console logs at Warning or higher and one concise final summary. Do not replay progress redraws, successful-test output, or Information/Debug/Trace logs into model context. On failure/crash, show only the failing test/resource, root error, and relevant stack frames; deduplicate and cap each diagnostic response at 80 lines / 8 KiB. Never dump entire console/host/browser logs, HTML, TRX, or crash artifacts. Keep necessary artifacts size-bounded outside context, link them, and inspect exact bounded excerpts. Preserve the runner exit code through capture/filtering; disclose truncation. Silence alone does not establish a hang.
[Test], [TestCase], [TestFixture], [SetUp], [TearDown] attributesAssert.That, and use TestCase or TestCaseSource only when parameterization improves signal.NUnit3TestAdapter, Microsoft.NET.Test.Sdk, and NUnit.Analyzers when CLI discovery or analyzer coverage is missing.| Package | Purpose |
|---|---|
NUnit | Core testing framework |
NUnit3TestAdapter | VSTest adapter for dotnet test |
NUnit.Analyzers | Roslyn analyzers for NUnit best practices |
Microsoft.NET.Test.Sdk | Required for test discovery |
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
<PackageReference Include="NUnit" Version="4.*" />
<PackageReference Include="NUnit3TestAdapter" Version="4.*" />
<PackageReference Include="NUnit.Analyzers" Version="4.*">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
[TestFixture]
public class CalculatorTests
{
private Calculator _calculator;
[SetUp]
public void SetUp()
{
_calculator = new Calculator();
}
[TearDown]
public void TearDown()
{
_calculator?.Dispose();
}
[Test]
public void Add_TwoPositiveNumbers_ReturnsSum()
{
var result = _calculator.Add(2, 3);
Assert.That(result, Is.EqualTo(5));
}
[Test]
public void Divide_ByZero_ThrowsException()
{
Assert.Throws<DivideByZeroException>(() => _calculator.Divide(10, 0));
}
}
[TestFixture]
public class ValidationTests
{
[TestCase("", false)]
[TestCase("a", false)]
[TestCase("ab", false)]
[TestCase("abc", true)]
[TestCase("valid@email.com", true)]
public void IsValid_VariousInputs_ReturnsExpected(string input, bool expected)
{
var result = Validator.IsValid(input);
Assert.That(result, Is.EqualTo(expected));
}
[TestCase(1, 2, ExpectedResult = 3)]
[TestCase(-1, 1, ExpectedResult = 0)]
[TestCase(100, 200, ExpectedResult = 300)]
public int Add_TestCases_ReturnsExpectedResult(int a, int b)
{
return _calculator.Add(a, b);
}
}
[TestFixture]
public class OrderTests
{
private static IEnumerable<TestCaseData> OrderTestCases()
{
yield return new TestCaseData(
new Order { Items = new[] { new Item { Price = 10 }, new Item { Price = 20 } } },
30m
).SetName("TwoItems_CalculatesTotal");
yield return new TestCaseData(
new Order { Items = Array.Empty<Item>() },
0m
).SetName("EmptyOrder_ReturnsZero");
yield return new TestCaseData(
new Order { Items = new[] { new Item { Price = 100 } }, DiscountPercent = 10 },
90m
).SetName("WithDiscount_AppliesDiscount");
}
[TestCaseSource(nameof(OrderTestCases))]
public void CalculateTotal_VariousOrders_ReturnsExpected(Order order, decimal expected)
{
var result = order.CalculateTotal();
Assert.That(result, Is.EqualTo(expected));
}
}
[Test]
public void AssertionExamples()
{
// Equality
Assert.That(actual, Is.EqualTo(expected));
Assert.That(actual, Is.Not.EqualTo(other));
// Comparison
Assert.That(value, Is.GreaterThan(5));
Assert.That(value, Is.LessThanOrEqualTo(10));
Assert.That(value, Is.InRange(1, 100));
// String
Assert.That(str, Does.StartWith("Hello"));
Assert.That(str, Does.Contain("world"));
Assert.That(str, Does.Match(@"\d{3}-\d{4}"));
Assert.That(str, Is.EqualTo("HELLO").IgnoreCase);
// Collection
Assert.That(list, Has.Count.EqualTo(5));
Assert.That(list, Contains.Item("expected"));
Assert.That(list, Is.All.GreaterThan(0));
Assert.That(list, Is.Unique);
Assert.That(list, Is.Ordered);
Assert.That(list, Has.Exactly(3).Items.GreaterThan(10));
// Type
Assert.That(obj, Is.InstanceOf<MyClass>());
Assert.That(obj, Is.AssignableTo<IMyInterface>());
// Null
Assert.That(obj, Is.Null);
Assert.That(obj, Is.Not.Null);
// Boolean
Assert.That(condition, Is.True);
Assert.That(condition, Is.False);
// Exception
Assert.That(() => DoSomething(), Throws.TypeOf<InvalidOperationException>());
Assert.That(() => DoSomething(), Throws.Exception.With.Message.Contains("error"));
// Async
Assert.That(async () => await DoAsync(), Throws.Nothing);
}
[TestFixture]
public class AsyncServiceTests
{
private IAsyncService _service;
[SetUp]
public void SetUp()
{
_service = new AsyncService();
}
[Test]
public async Task GetDataAsync_ValidId_ReturnsData()
{
var result = await _service.GetDataAsync(1);
Assert.That(result, Is.Not.Null);
Assert.That(result.Id, Is.EqualTo(1));
}
[Test]
public void GetDataAsync_InvalidId_ThrowsException()
{
Assert.ThrowsAsync<NotFoundException>(
async () => await _service.GetDataAsync(-1));
}
[Test]
public async Task ProcessAsync_CancellationRequested_ThrowsOperationCanceled()
{
using var cts = new CancellationTokenSource();
cts.Cancel();
Assert.ThrowsAsync<OperationCanceledException>(
async () => await _service.ProcessAsync(cts.Token));
}
}
[TestFixture]
public class IntegrationTests
{
private static TestServer _server;
private HttpClient _client;
[OneTimeSetUp]
public void OneTimeSetUp()
{
// Runs once before all tests in fixture
_server = new TestServer(new WebHostBuilder().UseStartup<Startup>());
}
[OneTimeTearDown]
public void OneTimeTearDown()
{
// Runs once after all tests in fixture
_server?.Dispose();
}
[SetUp]
public void SetUp()
{
// Runs before each test
_client = _server.CreateClient();
}
[TearDown]
public void TearDown()
{
// Runs after each test
_client?.Dispose();
}
[Test]
public async Task GetEndpoint_ReturnsSuccess()
{
var response = await _client.GetAsync("/api/data");
Assert.That(response.IsSuccessStatusCode, Is.True);
}
}
[TestFixture]
[Category("Integration")]
public class DatabaseTests
{
[Test]
[Category("Slow")]
public void SlowDatabaseTest() { }
[Test]
[Category("Fast")]
public void FastDatabaseTest() { }
}
// Run specific categories:
// dotnet test --filter "Category=Fast"
// dotnet test --filter "Category!=Slow"
| Anti-Pattern | Why It's Bad | Better Approach |
|---|---|---|
| Multiple asserts without clear purpose | Hard to identify which assertion failed | One logical assertion per test or use Assert.Multiple |
| Test interdependence | Tests fail unpredictably | Each test should be independent |
| Hardcoded test data | Brittle tests | Use TestCase or TestCaseSource |
| Testing implementation details | Breaks on refactoring | Test behavior, not internals |
Missing [SetUp]/[TearDown] cleanup | Resource leaks | Always clean up resources |
| Classic Assert syntax | Less readable | Use constraint model (Assert.That) |
# Run all tests
dotnet test
# VSTest: concise console results; MTP uses its own progress/ANSI flags
dotnet test --logger "console;verbosity=minimal"
# Filter by name
dotnet test --filter "FullyQualifiedName~CalculatorTests"
# Filter by category
dotnet test --filter "Category=Unit"
# Run in parallel
dotnet test -- NUnit.NumberOfTestWorkers=4
[TestCase] and [TestCaseSource]Assert.Thatasync Task not async void[TearDown] or [OneTimeTearDown]まだレビューはありません。使ってみた感想をお寄せください。
概要と使いどころ
Route gh-aw workflow design/create/debug/upgrade requests to the right prompts.
日本語の概要は準備中です。原文の説明を表示しています。
Use a repo-root `.editorconfig` to configure free .NET analyzer and style rules. Use when a .NET repo needs rule severity, code-style options, section layout, or analyzer ownership made explicit. USE FOR: the repo needs a root .editorconfig; analyzer severity and style ownership are unclear; the team wants one source of truth for rule configuration. DO NOT USE FOR: choosing analyzers with no config change; formatting-only execution with no config ownership question. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.
日本語の概要は準備中です。原文の説明を表示しています。
Scans .NET code for ~50 performance anti-patterns across async, memory, strings, collections, LINQ, regex, serialization, and I/O with tiered severity classification. Use when analyzing .NET code for optimization opportunities, reviewing hot paths, or auditing allocation-heavy patterns.
日本語の概要は準備中です。原文の説明を表示しています。
Symbolicate the .NET runtime frames in an Android tombstone file. Extracts BuildIds and PC offsets from the native backtrace, downloads debug symbols from the Microsoft symbol server, and runs llvm-symbolizer to produce function names with source file and line numbers. USE FOR triaging a .NET MAUI or Mono Android app crash from a tombstone, resolving native backtrace frames in libmonosgen-2.0.so or libcoreclr.so to .NET runtime source code, or investigating SIGABRT, SIGSEGV, or other native signals originating from the .NET runtime on Android. DO NOT USE FOR pure Java/Kotlin crashes, managed .NET exceptions that are already captured in logcat, or iOS crash logs. INVOKES Symbolicate-Tombstone.ps1 script, llvm-symbolizer, Microsoft symbol server.
日本語の概要は準備中です。原文の説明を表示しています。
Symbolicate .NET runtime frames in Apple platform .ips crash logs (iOS, tvOS, Mac Catalyst, macOS). Extracts UUIDs and addresses from the native backtrace, locates dSYM debug symbols, and runs atos to produce function names with source file and line numbers. Automatically downloads .dwarf symbols from the Microsoft symbol server using Mach-O UUIDs. USE FOR triaging a .NET MAUI or Mono app crash from an .ips file on any Apple platform, resolving native backtrace frames in libcoreclr or libmonosgen-2.0 to .NET runtime source code, retrieving .ips crash logs from a connected iOS device or iPhone, or investigating EXC_CRASH, EXC_BAD_ACCESS, SIGABRT, or SIGSEGV originating from the .NET runtime. DO NOT USE FOR pure Swift/Objective-C crashes with no .NET components, or Android tombstone files. INVOKES Symbolicate-Crash.ps1 script, atos, dwarfdump, idevicecrashreport.
日本語の概要は準備中です。原文の説明を表示しています。
Design or review .NET solution architecture across modular monoliths, clean architecture, vertical slices, microservices, DDD, CQRS, and cloud-native boundaries without over-engineering. USE FOR: .NET architecture choices; layer and domain boundary review; service decomposition; clean architecture, vertical slice, DDD, CQRS, and modular monolith decisions. DO NOT USE FOR: unrelated stacks; generic tasks that do not need this specific guidance. INVOKES: inspect the repository context, edit targeted files, and run relevant build, test, lint, or validation commands when changes are made.
日本語の概要は準備中です。原文の説明を表示しています。