.NET Test

This documentation was generated with the assistance of AI. Please report any inaccuracies.

Run a .NET project or solution’s test suite through the .NET CLI (dotnet test), scoped to whatever the caller asked for — everything, a single class, a single method, a wildcard/namespace pattern, or a trait/category expression. This is the .NET/C# equivalent of iru-java-test. It is a read-only reporting skill: it runs tests and summarizes the outcome, it does not fix failures unless asked to as an explicit follow-up.

Purpose

iru-dotnet-test turns a loosely-specified request ("run the FooTests", "just the fast ones", "everything") into the correct dotnet test --filter invocation and a concise pass/fail summary. It exists so that running and narrowing down tests doesn’t require hand-composing filter-expression syntax each time, and so that a calling skill (or a human) gets back a short report instead of a full raw test-run log.

It is Windows-desktop aware. A new Step 0 parses the arguments, detects the host (Windows or not), classifies every .csproj (portable, net-windows*, WinUI, UI-test projects) and detects the test runner (VSTest or Microsoft.Testing.Platform, where dotnet test takes --project/--solution). On a Windows-desktop repository it adds TestCategory!=UI to every ordinary run so FlaUI UI tests never run by default, and appends -p:EnableWindowsTargeting=true on a non-Windows host. Off Windows it never runs the whole solution — a net*-windows* test project aborts the run even though the portable projects passed ("Microsoft.WindowsDesktop.App not found", exit 1 under VSTest, exit 150 under MTP) — but runs each portable test project separately and lists every Windows test project (or one referencing a WinUI project) as unverified (needs Windows). Multiple solution files or test projects with no solution make it ask which to target. A "Known quirks" section records what was verified on macOS with the .NET 10 SDK.

The new ui selector (also accepted with a lock: held line when the caller already owns the lock) runs --filter "TestCategory=UI" on the UI-test project only on a Windows host with an interactive desktop session: it takes the repository-wide .integration-test.lock (atomic mkdir, owner file, stale after 60 minutes, released on every exit path), builds the app the tests launch, runs them, and otherwise reports unverified. Skipped or not-run UI tests are never reported as passed.

A ui run follows the catalog’s UI contract (see Building user interfaces). Beyond FlaUI desktop tests it also runs a .NET command-line tool’s Terminal.Gui view tests ([TestCategory("UI")] in a portable test project, rendered through the ANSI driver), which run on any host with no lock and no app build. It sets UI_SCREENSHOTS_DIR (default <repo root>/.ui-screenshots), clears it only on a full UI run, validates every capture name against the <kind>/<Id>/<state>--<direction>--<theme>[--<variant>…​] layout (.png, or .txt for terminal captures), and reports screenshot counts per kind, malformed names, accessibility violations (Axe.Windows for desktop, the asserted tui-* checks for terminal UIs; count + rule ids) and the .ui-quality.yml level applied (enforce|report|off|none).

Purpose group

Plugin

Shipped by the iru-dotnet plugin of the ai-catalog marketplace (install with /plugin install iru-dotnet@ai-catalog; see Plugins).

Invocation

/iru-dotnet-test
/iru-dotnet-test <selector>

Inputs

Argument Required Description Default

selector

No

Names what to run: a test class, a class+method, several classes, a wildcard/namespace pattern, a trait/category expression, or a specific project/solution path. Mapped to the correct --filter expression per the table below.

None — omitting it runs the full suite (dotnet test; on a Windows-desktop repository UI-category tests are excluded and, off Windows, portable projects run one by one).

ui (selector)

No

Run the UI tests (TestCategory=UI). Desktop FlaUI tests are Windows-only, behind the shared .integration-test.lock; off Windows or without an interactive desktop session they are reported unverified. Terminal.Gui view tests of a command-line tool run on any host, without the lock. Captures and accessibility results are collected per the UI contract.

Not applicable.

lock: held

No

A key: value line, only meaningful with ui: the caller already holds .integration-test.lock, so this skill neither takes nor releases it.

Lock is taken and released by this skill.

The selector maps to dotnet test parameters as follows:

What the caller wants Parameter Example

Everything

(none)

dotnet test

A specific project or solution

positional path

dotnet test MySolution.sln

One test class

--filter with FullyQualifiedName~

dotnet test --filter "FullyQualifiedName~FooTests"

One method in a class

--filter with FullyQualifiedName~Class.Method

dotnet test --filter "FullyQualifiedName~FooTests.TestSomething"

Several classes/methods

--filter with | between clauses

dotnet test --filter "FullyQualifiedNameFooTests|FullyQualifiedNameBarTests"

Classes matching a name pattern

--filter with ~ (contains match)

dotnet test --filter "FullyQualifiedName~ServiceTests"

All classes in a namespace

--filter with the namespace as a ~ prefix

dotnet test --filter "FullyQualifiedName~MyProject.Services"

Excluding some classes/methods

--filter with !~

dotnet test --filter "FullyQualifiedName!~SlowTests"

Tests tagged with a category/trait

--filter with the trait’s property name

dotnet test --filter "Category=fast"

Excluding a category/trait

--filter with !=

dotnet test --filter "Category!=slow"

Trait/category boolean expression

--filter with &, |, !, parentheses

dotnet test --filter "Category=fast&Priority=1"

Windows desktop: ordinary run

the selector’s filter AND TestCategory!=UI

dotnet test tests/App.Core.Tests --filter "(FullyQualifiedNameFooTests|FullyQualifiedNameBarTests)&TestCategory!=UI"

Windows desktop: UI tests (ui)

--filter "TestCategory=UI" on the UI-test project (Windows only, lock)

dotnet test tests/App.UITests --filter "TestCategory=UI"

Terminal UI tests (ui)

--filter "TestCategory=UI" on the portable test project referencing Terminal.Gui (any host, no lock)

dotnet test tests/Tool.Cli.Tests --filter "TestCategory=UI"

Which trait/category property name applies depends on the test framework in use (MSTest: TestCategory/ Priority; NUnit: Category; xUnit: whatever key was passed to [Trait("Key","Value")]) — checked against the test project’s <PackageReference> entries if unsure. A selector matching nothing reports "No test matches the given testcase filter" and exits successfully having run zero tests, rather than failing the build the way Maven Surefire does — called out explicitly in the report rather than treated as a pass.

Outputs

  • A plain-text summary in the conversation — never a written file.

  • Total tests run, passed, failed, and skipped, per test project.

  • If everything passed: a brief confirmation, without pasting the full log.

  • If there are failures: the failing test names and the relevant assertion/exception output (falling back to the .trx log under TestResults/ if console output was truncated) — without unrelated passing-test noise.

  • For a Windows-desktop repository: which test projects ran, which were unverified (needs Windows) and why, whether the default UI exclusion applied, and — for ui — how the lock behaved.

  • For ui runs (desktop and terminal): the screenshot directory and whether it was cleared (full run) or kept (scoped run); screenshot count per kind and per <kind>/<Id>; malformed capture names; the .ui-quality.yml accessibility level applied (or "missing — defaults"); accessibility violations as count + rule ids per context; and "captures unverified (needs Windows)" whenever the desktop stage could not run.

  • No source or test code is ever modified.

Execution flow

flowchart TD A["Start /dotnet-test\n(optional selector)"] --> A2["Step 0: parse arguments; detect host,\nWindows-desktop projects, UI tests, runner"] A2 --> A3{ui selector?} A3 -- "yes, Windows + desktop session" --> U["Take .integration-test.lock; build app;\nrun TestCategory=UI; release lock"] A3 -- "yes, terminal UI tests" --> U3["Run TestCategory=UI on the portable\nTerminal.Gui test project (any host, no lock)"] A3 -- "yes, otherwise" --> U2["Run nothing: report unverified"] A3 -- no --> B{Selector given?} B -- no --> C["Run dotnet test\n(full suite)"] B -- yes --> D["Map selector to --filter expression\n(and/or project/solution path)"] D --> E["Compose dotnet test command: mapped filter\n+ TestCategory!=UI; EnableWindowsTargeting off Windows;\nportable projects one by one off Windows"] E --> F["Run via Bash tool"] C --> F F --> G["Summarize output:\nrun / passed / failed / skipped per project"] G --> H{Failures?} H -- yes --> I["Show failing test names +\nassertion/exception output\n(.trx log if truncated)"] H -- no --> J["Report: all passed, briefly"] U --> U4["Resolve UI_SCREENSHOTS_DIR, read .ui-quality.yml;\nvalidate capture names; count accessibility violations"] U3 --> U4 U4 --> G

Dependencies

Invokes

None — iru-dotnet-test is a leaf skill; it only runs dotnet test and reports on its output, it does not call any other skill in this catalog.

Invoked by

  • .NET Code One Task Group — Step 3, once per task group’s bucket, via the iru-gate-runner agent, to run the scoped tests for every type the bucket affected (falling back to dotnet test --filter "FullyQualifiedName~<TestClass>" directly if this skill is unavailable), plus a full-suite run (this skill with no selector, so UI tests are excluded and non-runnable projects skipped).

  • Windows Code One Task Group — the scoped and full runs for Windows desktop app buckets, plus the ui selector on Windows (with lock: held when it already owns the lock), via iru-gate-runner.

  • .NET Generate All Tests — Step 7, once, to confirm the full suite still passes after every class’s tests have been written or extended; and Step 7b, with the ui selector, to run the newly generated UI tests; also delegated through iru-gate-runner.

Source

SKILL.md on GitHub — the file this page was generated from.