Precept 0.10.0

Filtering

Two filters, one expression language. --precept-filter selects among the tests a run has; the Filter section of precept.json decides which tests the run has at all.

Selecting from the command line#

dotnet run --project Checkout.Tests -- --precept-filter "smoke and not slow"
dotnet run --project Checkout.Tests -- --precept-filter "(@api or @web) and not @wip"
dotnet run --project Checkout.Tests -- --precept-filter "name:*checkout*"

The value must not start with @: Microsoft.Testing.Platform reads a leading @ as a response-file reference and will look for a file by that name. Write "smoke and not @slow" or wrap the whole thing in parentheses.

Removing tests from an environment#

Some tests have no business running somewhere: a suite that creates and deletes records, a pack that needs a payment sandbox, browser tests on an agent with no browsers. [Ignore] is the wrong tool — it reports them as skipped, they still clutter the report, and they still sit in the test explorer waiting for someone to click Run.

{
  "Filter": {
    "Include": "smoke or regression",
    "Exclude": "wip or name:*PayPal* or class:*.LegacyTests"
  }
}

A test survives when Include is empty or matches it, and Exclude is empty or does not. Anything else is gone before discovery reports a thing: not published to the test explorer, not reachable by --precept-filter, not reachable by uid from a stale explorer tree, and — when a class loses every test it had — its [BeforeSuite] and [AfterSuite] hooks never run either.

Both are single expressions rather than lists of tags, which is what makes them overridable. precept.prod.json replaces the base filter outright, an empty string clears it, and PRECEPT_FILTER__EXCLUDE overrides both from CI:

{ "Filter": { "Exclude": "wip" } }

A JSON array could do neither: IConfiguration merges arrays element by element across overlays, and an empty one clears nothing.

The expression language#

Form Matches
smoke, @smoke, tag:smoke a test category
name:Checkout the test's display name
class:LegacyTests the declaring class, by name or full name

Operands combine with and, or, not, parentheses and the &&/||/! spellings; not binds tightest, then and, then or. Matching is case-insensitive throughout and the leading @ on a tag is optional.

Every operand is a glob — * for any run of characters, ? for one — so a substring match is name:*checkout*, and a pattern with no wildcard is an exact match. Wrap anything with spaces in double quotes, which also protects parentheses and operator words:

name:"A customer checks out (with a card)"

Precept 0.10.0 · MIT · © 2026

Esc