GeorgJung.TUnit.PairwiseDataSource
0.1.28
dotnet add package GeorgJung.TUnit.PairwiseDataSource --version 0.1.28
NuGet\Install-Package GeorgJung.TUnit.PairwiseDataSource -Version 0.1.28
<PackageReference Include="GeorgJung.TUnit.PairwiseDataSource" Version="0.1.28" />
<PackageVersion Include="GeorgJung.TUnit.PairwiseDataSource" Version="0.1.28" />
<PackageReference Include="GeorgJung.TUnit.PairwiseDataSource" />
paket add GeorgJung.TUnit.PairwiseDataSource --version 0.1.28
#r "nuget: GeorgJung.TUnit.PairwiseDataSource, 0.1.28"
#:package GeorgJung.TUnit.PairwiseDataSource@0.1.28
#addin nuget:?package=GeorgJung.TUnit.PairwiseDataSource&version=0.1.28
#tool nuget:?package=GeorgJung.TUnit.PairwiseDataSource&version=0.1.28
TUnit.PairwiseDataSource
A TUnit plugin that provides pairwise (all-pairs) test case generation. Instead of testing every possible combination of parameter values (Cartesian product), pairwise testing generates a smaller set of test cases that covers every pair of parameter values at least once.
This project is closely based on Xunit.Combinatorial by Andrew Arnott. In particular, the harder parts of the pairwise generation logic are intentionally kept very close to that codebase rather than being a fresh reimplementation. That close ancestry is deliberate: one goal of this package is to make xUnit to TUnit migration easier, including preserving the same generated pairwise cases for equivalent inputs.
Why pairwise?
Research shows most software defects are triggered by interactions between at most two parameters. Pairwise testing exploits this by covering all two-way interactions with significantly fewer test cases:
| Parameters | Values each | Cartesian product | Pairwise |
|---|---|---|---|
| 3 | 3 | 27 | 9 |
| 4 | 3 | 81 | 9 |
| 5 | 3 | 243 | 15 |
| 3 bools | 2 | 8 | 4 |
Installation
dotnet add package TUnit.PairwiseDataSource
Usage
Use [PairwiseDataSource] in place of [MatrixDataSource] on your test methods. Parameter values are specified the same way, using [Matrix(...)] attributes:
using TUnit.PairwiseDataSource;
[Test, PairwiseDataSource]
public async Task MyTest(
[Matrix("a", "b", "c")] string first,
[Matrix("+", "-")] string op,
[Matrix("x", "y")] string second)
{
// Generates 6 test cases covering all pairs, instead of 12 (3×2×2) combinations
}
Automatic value generation
Just like [MatrixDataSource], boolean and enum parameters don't need explicit [Matrix(...)] attributes:
public enum Priority { Low, Medium, High }
[Test, PairwiseDataSource]
public async Task TestWithAutoValues(bool enabled, Priority priority)
{
// Generates pairwise combinations of {true,false} × {Low,Medium,High}
}
Exclusions
Use [MatrixExclusion(...)] to exclude specific combinations:
[Test, PairwiseDataSource]
[MatrixExclusion("a", "+", "x")]
public async Task MyTest(
[Matrix("a", "b", "c")] string first,
[Matrix("+", "-")] string op,
[Matrix("x", "y")] string second)
{
// The combination ("a", "+", "x") will never appear
}
Migrating from Xunit.Combinatorial
If you're migrating from xUnit with Xunit.Combinatorial, the mapping is straightforward.
That migration story is not accidental. This package is deliberately built on the same underlying approach, and the pairwise strategy was ported closely enough that equivalent inputs produce the same pair sets. In practice, that means moving from xUnit to TUnit does not also force you to absorb a silent change in generated test cases.
| Xunit.Combinatorial | TUnit + PairwiseDataSource |
|---|---|
[Theory, PairwiseData] |
[Test, PairwiseDataSource] |
[Theory, CombinatorialData] |
[Test, MatrixDataSource] |
[CombinatorialValues(1, 2, 3)] |
[Matrix(1, 2, 3)] |
[CombinatorialRange(0, 5)] |
[MatrixRange<int>(0, 5)] |
| Bool/enum auto-generation | Bool/enum auto-generation (same) |
Example migration
Before (xUnit):
[Theory, PairwiseData]
public void MyTest(
[CombinatorialValues("a", "b", "c")] string x,
[CombinatorialValues("+", "-")] string y,
[CombinatorialValues("1", "2")] string z)
{
}
After (TUnit):
[Test, PairwiseDataSource]
public async Task MyTest(
[Matrix("a", "b", "c")] string x,
[Matrix("+", "-")] string y,
[Matrix("1", "2")] string z)
{
}
Analyzer: TUnit0049 and PWTUNIT001
TUnit's built-in analyzer emits TUnit0049 when [Matrix] is used without [MatrixDataSource]. It doesn't know about [PairwiseDataSource], so this package suppresses TUnit0049 automatically for NuGet consumers via its shipped build props.
This package ships a replacement analyzer (PWTUNIT001) that provides equivalent protection: it errors when [Matrix] is used on parameters but neither [MatrixDataSource] nor [PairwiseDataSource] is present. So after suppressing TUnit0049, you still get a build error if you forget the data source attribute.
Advanced package options
The package also exposes two optional MSBuild properties for consuming projects. Both are enabled by default, so you only need to set them if you want to opt out:
<PropertyGroup>
<TUnitPairwiseDataSourceImplicitUsings>false</TUnitPairwiseDataSourceImplicitUsings>
<TUnitPairwiseDataSourceSuppressTUnit0049>false</TUnitPairwiseDataSourceSuppressTUnit0049>
</PropertyGroup>
TUnitPairwiseDataSourceImplicitUsingsAdds the implicitusing TUnit.PairwiseDataSource;for you. Set it tofalseif you prefer explicitusingstatements.TUnitPairwiseDataSourceSuppressTUnit0049Suppresses TUnit'sTUnit0049analyzer diagnostic automatically. Set it tofalseif you want to keep TUnit's original diagnostic visible.
Algorithm
The pairwise test case generation algorithm in this repository is not merely inspired by Xunit.Combinatorial. PairwiseStrategy.cs is a close port of Andrew Arnott's implementation, preserving its behavior intentionally so that migrations can keep the exact same pairwise coverage.
That implementation in Xunit.Combinatorial is itself derived from Charlie Poole's NUnit implementation, originally based on Bob Jenkins' "jenny" tool.
Xunit.Combinatorial is an excellent project, and this package benefits directly from that work. The goal here is not to obscure that lineage, but to bring the same proven pairwise behavior into TUnit with an API that fits naturally alongside [MatrixDataSource].
License
This project is licensed under the MIT License - see LICENSE for details.
The pairwise algorithm implementation (PairwiseStrategy.cs) is derived from Xunit.Combinatorial by Andrew Arnott (itself based on Charlie Poole's NUnit implementation) and is licensed under the Microsoft Public License (Ms-PL). See ThirdPartyNotices.txt for the full license text.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- TUnit.Core (>= 1.19.57)
-
net10.0
- TUnit.Core (>= 1.19.57)
-
net8.0
- TUnit.Core (>= 1.19.57)
-
net9.0
- TUnit.Core (>= 1.19.57)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.28 | 38 | 3/19/2026 |
| 0.1.27-g93188eced2 | 28 | 3/19/2026 |