Query Filter Language

Last updated: 2024 December 16

New in v3 is support for an advanced query filter language. It is inspired by the MSTest Graph Query Filter, but with several differences in final implementation.

The intention of the query filter language is to allow a more powerful and flexible way to filter tests than the existing simple filters (which allow filtering based on namespace, fully qualified class names, fully qualified method names, and traits).

Note: In order to better reason about how filtering works, you may use either query filters or simple filters, but you may not use both at the same time.

Query filter language

Below is a list of components of the query language.

Note: All string comparisons are done case insensitively. That means /foo and /FOO are the same query.

Query is segmented

The query filter supported in xUnit.net v3 is structured with between one and four segments:

/<assemblyFilter>/<namespaceFilter>/<classFilter>/<methodFilter>

The four segments represent the four parts of a fully qualified test method in an assembly. For the purposes of illustration, let’s assume a test method of MyNamespace.MySubNamespace.MyClass+MySubClass.MyTestMethod that lives in C:\Dev\MyProjects\Tests\bin\Debug\net8.0\MyTests.dll:

Example:

/MyTests/MyNamespace.MySubNamespace/MyClass+MySubClass/MyTestMethod will match the example test method above.

Use a wildcard in a segment to indicate a “match all”

For any segment, you can use * to represent a “match all”.

In addition, any segment left off the query is considered to be an implicit “match all”.

Examples:

Note: Queries must always start with /, even if you are not specifying any segment values. Specifying more than four segments results in a parsing error for the query.

Use a trait filter

To filter based on a trait, add an appropriate trait expression to the end of your query, in the form of [name=value] or [name!=value].

Examples:

Use wildcards to start/end a query expression

You may start and/or end a query expression with * to indicate a wildcard that matches 0 or more characters. This includes both segment query expressions as well as the name and/or value portion of a trait filter.

Query segment examples:

Trait filter example:

Note: The * wildcard is only allowed at the start or end, and not in the middle, of any query.

Note: In v3, all simple queries have been updated to support this same start and/or end wildcards, including using wildcards for trait names and/or values. In v2, only the simple method query supported wildcards.

Combine multiple queries in a single segment

Within a single segment (or within a trait query), you may combine multiple matching patterns by using parenthesis, separated by either | (for OR) or & (for AND). Parenthesis in this situation are not optional.

If your multipart query contains three or more pieces, they must either be all the same type (OR vs. AND), or must use extra parenthesis to indicate how the operators are to be grouped. A query like (A)|(B)|(C) is legal, but (A)|(B)&(C) is not and must be expressed either as ((A)|(B))&(C) or (A)|((B)&(C)).

Multipart queries cannot span across segment boundaries.

Examples:

Negate a segment query

You may negate a segment query by prepending ! on the segment filter expression.

Note: If you are using wildcard expressions, the negate operator comes before the wildcard (i.e., !*, not *!). If you are combining multiple queries in a single segment, the negate operator is placed inside the parenthesis, not outside (i.e., (!expression), not !(expression)).

Examples:

Note: Negating a trait query is done by using [name!=value], not ![name=value].

Escaping special characters

You can escape special characters (like ( and )) and any other character your terminal might not directly support by encoding them using the hexadecimal HTML character encoding scheme. Escape the value with &#x1234; where 1234 is the 1-4 digit hex code for a UTF-16 character.

Commonly escaped special characters:

Specifying a query filter

The way you pass a query filter depends on whether you’re interacting with an xUnit.net CLI or not.

If you specify more than one query filter, they run in a logical OR mode; that is, tests which may any one of the filters will match.

Note: If you are using dotnet run or dotnet test to run your tests, passing command line options must be done after you pass -- first, so that the dotnet executable knows how to differentiate between command line switches meant for dotnet (before the --) vs. command line switches meant for the test project (after the --).

Running a test project directly (xUnit.net CLI mode), via dotnet run, or via xunit.v3.console.exe

You can specify a query filter using -filter expression (note that if the expression contains spaces, you should quote the whole expression, like -filter "expression" so that the parser knows where your expression starts and ends).

If you’re using xunit.v3.console.exe and you’re running multiple test projects, then the query is passed to all test projects. Ensure that your query filter includes an assembly name filter segment if the filter is only intended to match tests from a subset of the test projects.

Examples:

Running a test project directly (Microsoft Testing Platform CLI mode) or via dotnet test

You can specify a query filter using --query-filter expression (note that if the expression contains spaces, you should quote the whole expression, like --query-filter "expression" so that the parser knows where your expression starts and ends).

Examples:

Copyright © .NET Foundation. Contributions welcomed at https://github.com/xunit/xunit/tree/gh-pages.