Skip to content
Purview Dev logo

Testing Wiring

Stable Build SDK Reviewed 2026-10-13 purview-dev/build-sdk Star on GitHub 1 central-package-management code-style csharp developer-experience developer-tooling devex dotnet msbuild msbuild-sdk nuget project-templates roslyn roslyn-analyzers roslyn-generators tunit xunit

This page explains how the SDK implements the higher-level testing conventions in Engineering Principles.

The SDK wires the testing stack for you based on three properties that must be set before the SDK import:

PropertyDefaultDescription
TestingFrameworkTUnitTesting framework. Supported values: TUnit, Xunit, None.
SubstituteFrameworkTUnitMocksMocking provider. Supported values: TUnitMocks, NSubstitute, None.
TestDataFrameworkBogusTest data provider. Supported values: Bogus, None.

All three are validated at build/restore/pack time, and invalid values fail the build with a clear error.

  • OutputType=Exe, TestingPlatformDotnetTestSupport=true, UseMicrosoftTestingPlatformRunner=true, EnableMicrosoftTestingPlatform=true.
  • The TUnit package is referenced (with the Microsoft.Testing.Platform runner configured via global.json).
  • A [Category: <TestingType>] assembly attribute tags every test with its detected test category (for example Unit, Integration), which makes --treenode-filter filtering work. That category is the default classification, not a limit on adding more categories.
  • TUnit.Mocks is referenced when SubstituteFramework=TUnitMocks (the default).
  • Bogus is referenced when TestDataFramework=Bogus (the default).

Set TestingFramework=Xunit:

  • xunit.v3 and xunit.runner.visualstudio (private assets) are referenced.
  • A [Trait("Category", "<TestingType>")] assembly attribute tags every test.
  • OutputType=Exe when the testing framework is not None.

Set TestingFramework=None to disable the test runner wiring entirely. The test project is still detected and gets coverage/IVT behaviour, but no framework packages or runner configuration are added.

All test and shared-testing projects get:

  • A test-context rule set (PurviewTestContextNoWarn, overridable before the SDK import): the production API-surface rules (CA1002, CA1012, CA1034, CA1047, CA1050, CA1051, CA1062, CA1064, CA1515, CA1707) are exempt, because test classes/fixtures are public, test names use Method_Scenario_Expectation, and helpers take unvalidated fixture parameters. Style rules (IDE0040, field naming, formatting, IDE1006 naming) are still enforced. DisablePurviewTestContextRuleSet=true enforces the production rules too.
  • CollectCoverage=true with coverage exclusions for [NSubstitute*], [TUnit.*], [xunit.*], [Microsoft.Testing.*], [Microsoft.NET.Test*], and [Bogus*].
  • ExcludeByAttribute for ExcludeFromCodeCoverageAttribute.
  • IsPackable=false, IsPublishable=false, MaxCpuCount=0, DisableGenerateAssemblyInfoClass=true, DisableGenerateAssemblyIdentifierClass=true (the test assembly is the one asserting, so it has nothing to identify — see Assembly identifier class).
  • Disabled native instrumentation.
  • An [assembly: ExcludeFromCodeCoverage] attribute.
  • TUnitMocks (default) — references TUnit.Mocks.
  • NSubstitute — references NSubstitute plus NSubstitute.Analyzers.CSharp (analyzers, private assets) and a global using NSubstitute.
  • None — no mocking package.
  • Bogus (default) — references Bogus with a global using Bogus.
  • None — no data package.

Projects named SharedTestingFramework, SharedTestingInfrastructure, SharedTestingInfra, SharedTestingUtilities, SharedTestingUtils, SharedTestingLibrary, SharedTestingLib, or SharedTestingHelpers are treated as shared testing helpers:

  • They get the test package references (TUnit.Core rather than the full TUnit) but not the test runner or coverage settings.
  • A [Skip] attribute (TUnit) keeps the shared assembly from being executed directly.
  • They are forced to OutputType=Library (with IsTestProject/IsTestingPlatformApplication cleared) after package props run, because test packages such as TUnit.Engine otherwise turn them into executable test hosts - which would make CA1515 demand that their fixtures become internal while the test assemblies still consume them. Set PurviewSharedTestingOutputType=Exe before the SDK import to opt back into that shape.
  • Test projects automatically reference the sibling shared testing project via ../SharedTesting*/SharedTesting*.csproj.

Test projects automatically reference their target project. The SDK probes ../<TargetProjectName>/, ../../<TargetProjectName>/, ../src/<TargetProjectName>/, and ../../src/<TargetProjectName>/ (whichever exists), so both the src/+tests/ and flat layouts are covered.

Tests use Microsoft.Testing.Platform (global.json sets "runner": "Microsoft.Testing.Platform") and are filtered with TUnit tree-node filters:

Terminal window
dotnet test --treenode-filter "/*/*/*/*[Category=Unit]/"

See Project Naming Conventions for the recognised test suffixes and InternalsVisibleTo for how test assemblies access internals.