Skip to content

Commit 074a779

Browse files
authored
Docs (#3371)
* Docs Add Global Timeout section to repeating.md Add Global Timeout section to timeouts.md * Add Global Skipping section to skip.md * Provide documentation for 1. ExplicitAttribute 2. NotInParallelAttribute 3. RepeatAttribute 4. SkipAttribute * Small fix * Add docs for ArgumentsAttribute and MatrixAttribute
1 parent 27a978e commit 074a779

File tree

8 files changed

+271
-4
lines changed

8 files changed

+271
-4
lines changed

TUnit.Core/Attributes/TestData/ArgumentsAttribute.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,33 @@
22

33
namespace TUnit.Core;
44

5+
/// <summary>
6+
/// Provides a way to supply inline data for parameterized tests.
7+
/// </summary>
8+
/// <remarks>
9+
/// <para>
10+
/// The <c>ArgumentsAttribute</c> allows you to specify test data directly within your test definition,
11+
/// rather than having to create a separate data source class.
12+
/// </para>
13+
/// <para>
14+
/// Each attribute instance represents a single test case that will be executed.
15+
/// </para>
16+
/// <para>
17+
/// Multiple <c>ArgumentsAttribute</c> instances can be applied to a single test method to create
18+
/// multiple test cases with different input values.
19+
/// </para>
20+
/// <example>
21+
/// <code>
22+
/// [Test]
23+
/// [Arguments(1, 2, 3)]
24+
/// [Arguments(10, 20, 30)]
25+
/// public void TestAddition(int a, int b, int expected)
26+
/// {
27+
/// Assert.That(a + b).IsEqualTo(expected);
28+
/// }
29+
/// </code>
30+
/// </example>
31+
/// </remarks>
532
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)]
633
public sealed class ArgumentsAttribute : Attribute, IDataSourceAttribute, ITestRegisteredEventReceiver
734
{
@@ -29,7 +56,7 @@ public ArgumentsAttribute(params object?[]? values)
2956

3057
public ValueTask OnTestRegistered(TestRegisteredContext context)
3158
{
32-
if(!string.IsNullOrEmpty(Skip))
59+
if (!string.IsNullOrEmpty(Skip))
3360
{
3461
context.TestContext.SkipReason = Skip;
3562
context.TestContext.TestDetails.ClassInstance = SkippedTestInstance.Instance;
@@ -54,7 +81,7 @@ public override async IAsyncEnumerable<Func<Task<T>>> GetTypedDataRowsAsync(Data
5481

5582
public ValueTask OnTestRegistered(TestRegisteredContext context)
5683
{
57-
if(!string.IsNullOrEmpty(Skip))
84+
if (!string.IsNullOrEmpty(Skip))
5885
{
5986
context.TestContext.SkipReason = Skip;
6087
context.TestContext.TestDetails.ClassInstance = SkippedTestInstance.Instance;

TUnit.Core/Attributes/TestData/MatrixSourceAttribute.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,45 @@
22

33
namespace TUnit.Core;
44

5+
/// <summary>
6+
/// Provides a way to specify discrete values for a test parameter.
7+
/// When multiple parameters use the <see cref="MatrixAttribute"/>, TUnit will generate tests for all combinations.
8+
/// </summary>
9+
/// <remarks>
10+
/// <para>
11+
/// The Matrix attribute creates a combinatorial test matrix when used on multiple parameters.
12+
/// Each parameter decorated with <see cref="MatrixAttribute"/> contributes its values to the combinations.
13+
/// </para>
14+
/// <para>
15+
/// Example:
16+
/// <code>
17+
/// [Test]
18+
/// public void MatrixTest(
19+
/// [Matrix(1, 2)] int x,
20+
/// [Matrix("a", "b")] string y)
21+
/// {
22+
/// // This will run 4 test cases:
23+
/// // x=1, y="a"
24+
/// // x=1, y="b"
25+
/// // x=2, y="a"
26+
/// // x=2, y="b"
27+
/// }
28+
/// </code>
29+
/// </para>
30+
/// <para>
31+
/// You can exclude specific values from the matrix by using the <c>Excluding</c> property:
32+
/// <code>
33+
/// [Test]
34+
/// public void MatrixWithExclusionsTest(
35+
/// [Matrix(1, 2, 3) { Excluding = [3] }] int x,
36+
/// [Matrix("a", "b")] string y)
37+
/// {
38+
/// // This will exclude combinations with x=3
39+
/// }
40+
/// </code>
41+
/// </para>
42+
/// </remarks>
43+
/// <param name="objects">The values to be used for this parameter in the test matrix.</param>
544
[AttributeUsage(AttributeTargets.Parameter)]
645
public class MatrixAttribute(params object?[]? objects) : TUnitAttribute
746
{
@@ -14,5 +53,6 @@ protected MatrixAttribute() : this(null)
1453
public object?[]? Excluding { get; init; }
1554
}
1655

56+
/// <inheritdoc/>
1757
[AttributeUsage(AttributeTargets.Parameter)]
1858
public class MatrixAttribute<T>(params T?[]? objects) : MatrixAttribute(objects?.Cast<object>().ToArray()), IInfersType<T>;

TUnit.Core/Attributes/TestMetadata/NotInParallelAttribute.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,49 @@
22

33
namespace TUnit.Core;
44

5+
/// <summary>
6+
/// Specifies that a test method, test class, or assembly should not be executed in parallel with other tests that share the same constraint keys.
7+
/// </summary>
8+
/// <remarks>
9+
/// The NotInParallelAttribute helps control test execution to prevent tests from interfering with each other when they
10+
/// access shared resources. When multiple tests share the same constraint key, they will be executed sequentially rather than in parallel.
11+
///
12+
/// NotInParallel can be applied at the method, class, or assembly level.
13+
/// When applied at a class level, all test methods in the class will follow the parallel execution constraint.
14+
/// When applied at the assembly level, it affects all tests in the assembly.
15+
///
16+
/// Method-level attributes take precedence over class-level attributes, which take precedence over assembly-level attributes.
17+
///
18+
/// Tests with no overlapping constraint keys can still run in parallel with each other.
19+
/// To prevent a test from running in parallel with any other test, use the attribute without specifying constraint keys.
20+
/// </remarks>
21+
/// <example>
22+
/// <code>
23+
/// // Prevent this test from running in parallel with any other test with the "Database" constraint key
24+
/// [Test]
25+
/// [NotInParallel("Database")]
26+
/// public void TestThatAccessesDatabase()
27+
/// {
28+
/// // This test will not run in parallel with any other test that has the "Database" constraint
29+
/// }
30+
///
31+
/// // Prevent this test from running in parallel with tests that have either "Api" or "Database" constraint keys
32+
/// [Test]
33+
/// [NotInParallel(new[] { "Api", "Database" })]
34+
/// public void TestThatAccessesMultipleResources()
35+
/// {
36+
/// // This test will not run in parallel with tests that have "Api" or "Database" constraints
37+
/// }
38+
///
39+
/// // Prevent this test from running in parallel with any other test
40+
/// [Test]
41+
/// [NotInParallel]
42+
/// public void TestThatMustRunIsolated()
43+
/// {
44+
/// // This test will run exclusively
45+
/// }
46+
/// </code>
47+
/// </example>
548
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
649
public class NotInParallelAttribute : SingleTUnitAttribute, ITestDiscoveryEventReceiver, IScopedAttribute
750
{

TUnit.Core/Attributes/TestMetadata/RepeatAttribute.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,52 @@
11
namespace TUnit.Core;
22

3+
/// <summary>
4+
/// Specifies that a test method, test class, or assembly should be repeated a specified number of times.
5+
/// </summary>
6+
/// <remarks>
7+
/// The RepeatAttribute causes the test to be executed the specified number of times.
8+
/// This is useful for testing consistency across multiple executions or for stress testing.
9+
///
10+
/// Repeat can be applied at the method, class, or assembly level.
11+
/// When applied at a class level, all test methods in the class will be repeated.
12+
/// When applied at the assembly level, it affects all tests in the assembly.
13+
///
14+
/// Method-level attributes take precedence over class-level attributes, which take precedence over assembly-level attributes.
15+
/// </remarks>
16+
/// <example>
17+
/// <code>
18+
/// [Test]
19+
/// [Repeat(5)]
20+
/// public void TestThatShouldBeConsistent()
21+
/// {
22+
/// // This test will run 5 times
23+
/// Assert.That(MyFunction()).IsTrue();
24+
/// }
25+
///
26+
/// [Test]
27+
/// [Repeat(100)]
28+
/// public void StressTest()
29+
/// {
30+
/// // /Run this test 100 times to ensure reliability under load
31+
/// var result = ComplexOperation();
32+
/// Assert.That(result).IsValid();
33+
/// }
34+
/// </code>
35+
/// </example>
336
// Don't think there's a way to enable inheritance on this because the source generator needs to access the constructor argument
437
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)]
538
public sealed class RepeatAttribute : TUnitAttribute, IScopedAttribute
639
{
40+
/// <summary>
41+
/// Gets the number of times the test should be repeated.
42+
/// </summary>
743
public int Times { get; }
844

45+
/// <summary>
46+
/// Initializes a new instance of the <see cref="RepeatAttribute"/> class with the specified number of repetitions.
47+
/// </summary>
48+
/// <param name="times">The number of times to repeat the test. Must be a non-negative integer.</param>
49+
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="times"/> is less than 0.</exception>
950
public RepeatAttribute(int times)
1051
{
1152
if (times < 0)

TUnit.Core/Attributes/TestMetadata/SkipAttribute.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,40 @@
22

33
namespace TUnit.Core;
44

5+
/// <summary>
6+
/// Specifies that a test method, test class, or assembly should be skipped during test execution.
7+
/// </summary>
8+
/// <remarks>
9+
/// When applied to a test method, class, or assembly, the SkipAttribute prevents the test(s) from being executed
10+
/// and marks them as skipped with the provided reason.
11+
///
12+
/// Skip can be applied at the method, class, or assembly level.
13+
/// When applied at a class level, all test methods in the class will be skipped.
14+
/// When applied at the assembly level, it affects all tests in the assembly.
15+
/// </remarks>
16+
/// <example>
17+
/// <code>
18+
/// [Test]
19+
/// [Skip("Not implemented yet")]
20+
/// public void TestThatIsNotReady()
21+
/// {
22+
/// // This test will be skipped with the reason "Not implemented yet"
23+
/// }
24+
///
25+
/// // Example of a custom skip attribute with conditional logic
26+
/// public class SkipOnLinuxAttribute : SkipAttribute
27+
/// {
28+
/// public SkipOnLinuxAttribute() : base("Test not supported on Linux")
29+
/// {
30+
/// }
31+
///
32+
/// public override Task&lt;bool&gt; ShouldSkip(TestRegisteredContext context)
33+
/// {
34+
/// return Task.FromResult(System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux));
35+
/// }
36+
/// }
37+
/// </code>
38+
/// </example>
539
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)]
640
public class SkipAttribute : Attribute, ITestRegisteredEventReceiver
741
{
@@ -26,5 +60,19 @@ public async ValueTask OnTestRegistered(TestRegisteredContext context)
2660
}
2761
}
2862

63+
/// <summary>
64+
/// Determines whether a test should be skipped.
65+
/// </summary>
66+
/// <param name="context">The test context containing information about the test being registered.</param>
67+
/// <returns>
68+
/// A task that represents the asynchronous operation.
69+
/// The task result is true if the test should be skipped; otherwise, false.
70+
/// </returns>
71+
/// <remarks>
72+
/// Can be overridden in derived classes to implement conditional skip logic
73+
/// based on specific conditions or criteria.
74+
///
75+
/// The default implementation always returns true, meaning the test will always be skipped.
76+
/// </remarks>
2977
public virtual Task<bool> ShouldSkip(TestRegisteredContext context) => Task.FromResult(true);
3078
}

docs/docs/execution/repeating.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,30 @@ public class MyTestClass
2222

2323
}
2424
}
25-
```
25+
```
26+
27+
## Global Repeat
28+
29+
In case you want to apply the repeat logic to all tests in a project, you can add the attribute on the assembly level.
30+
31+
```csharp
32+
[assembly: Repeat(3)]
33+
```
34+
35+
Or you can apply the repeat policy on all the tests in a class like this:
36+
37+
```csharp
38+
[Repeat(3)]
39+
public class MyTestClass
40+
{
41+
}
42+
```
43+
44+
The more specific attribute will always override the more general one.
45+
For example, the `[Repeat(3)]` on a method will override the `[Repeat(5)]` on the class,
46+
which in turn will override the `[Repeat(7)]` on the assembly.
47+
48+
So the order of precedence is:
49+
1. Method
50+
1. Class
51+
1. Assembly

docs/docs/execution/timeouts.md

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,30 @@ public class MyTestClass
2424

2525
}
2626
}
27-
```
27+
```
28+
29+
## Global Timeout
30+
31+
In case you want to apply the timeout to all tests in a project, you can add the attribute on the assembly level.
32+
33+
```csharp
34+
[assembly: Timeout(3000)]
35+
```
36+
37+
Or you can apply the Timeout on all the tests in a class like this:
38+
39+
```csharp
40+
[Timeout(3000)]
41+
public class MyTestClass
42+
{
43+
}
44+
```
45+
46+
The more specific attribute will always override the more general one.
47+
For example, the `[Timeout(3000)]` on a method will override the `[Timeout(5000)]` on the class,
48+
which in turn will override the `[Timeout(7000)]` on the assembly.
49+
50+
So the order of precedence is:
51+
1. Method
52+
1. Class
53+
1. Assembly

docs/docs/test-authoring/skip.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,19 @@ public class MyTestClass
4848
}
4949
```
5050

51+
## Global Skipping
52+
53+
In case you want to skip all tests in a project, you can add the attribute on the assembly level.
54+
55+
```csharp
56+
[assembly: Skip("Skipping all tests in this assembly")]
57+
```
58+
59+
Or you can skip all the tests in a class like this:
60+
61+
```csharp
62+
[Skip("Skipping all tests in this class")]
63+
public class MyTestClass
64+
{
65+
}
66+
```

0 commit comments

Comments
 (0)