Limitations

Where TestDetta cannot see something, it selects more. This page lists those places, so you know when a selection is wider than it needs to be, and the few cases where a hand-written pattern can hide a test.

Test frameworks and runners

Both dotnet test runners are supported. The runner is read from global.json ("test": { "runner": "Microsoft.Testing.Platform" }, required for xUnit v3 on the .NET 10 SDK).

Each test project is built and run in the directory of the nearest global.json at or above it, so a file kept next to the solution (src/global.json) counts as it does for a developer there. --dry-run prints such commands as (cd src && dotnet test ...).

Recording and selection are tested end to end with xUnit v2 (VSTest), xUnit v3 and TUnit (Microsoft.Testing.Platform), and MSTest and NUnit under both runners, including projects that turn on their framework's own parallelization.

Tests that fail while recording

Test classes that fail while recording are always selected when their project is affected: a failing test stops early, so its coverage is incomplete.

When tests fail and no TRX report says which (NUnit under Microsoft.Testing.Platform without Microsoft.Testing.Extensions.TrxReport), the map is not used and selection falls back to names.

Code that runs once per process

Caches, lazy singletons and EF model building run once per test process, and are credited to the first test class that triggers them. Changes to code that ran inside a static constructor or a cache-filling call (ConcurrentDictionary.GetOrAdd, Lazy<T>.Value, LazyInitializer, ConditionalWeakTable, IMemoryCache.GetOrCreate), and to constructors and static members that only one test class per recording process ran, are traced by name instead.

A cache written by hand, such as a Dictionary checked with TryGetValue, can still hide its users. Keep running the full suite on the default branch; recording does that.

Project files

Project files are evaluated by MSBuild (one dotnet msbuild call, cached in .testdetta/cache) for references, compiled and embedded items, assembly names and target frameworks, in the default configuration and without a restore.

Preprocessor symbols

C# files are parsed with each target framework's real preprocessor symbols, and also with no symbols and with every symbol their #ifs name, so code under any active condition is seen.

Skipped tests

Tests skipped while a map was recorded have no coverage. A class whose tests were all skipped is selected on another platform, where it may run, and skipped on the recording platform. Tests skipped for other reasons, such as a missing Docker daemon, are covered only by recording where the tests run.

Source generators

Code written by source generators is not in the source tree. td record reads it from the PDBs of the recorded assemblies (portable or embedded) and keeps the names it mentions in the map, so name tracing sees generated callers. Assemblies built without a portable PDB give nothing.

F# and Visual Basic

F# and Visual Basic projects are part of the project graph, but their code is not analysed: when one is affected, everything that depends on it runs completely.