Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 70 additions & 2 deletions TUnit.Core/Attributes/ParallelGroupAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,82 @@

namespace TUnit.Core;


/// <summary>
/// Specifies that a test method, class, or assembly belongs to a parallel execution group.
/// </summary>
/// <remarks>
/// <para>
/// Tests within the same parallel group will run in parallel with each other but not with tests from other groups.
/// This attribute helps to organize test execution when you want to control how certain tests run in relation to others.
/// </para>
/// <para>
/// The test engine processes parallel groups sequentially based on their <see cref="Order"/> property, but tests
/// within the same group execute in parallel with each other. This is useful for organizing tests that should
/// run concurrently but in separate batches from other test groups.
/// </para>
/// <para>
/// This attribute implements <see cref="ITestDiscoveryEventReceiver"/> to register a <see cref="ParallelGroupConstraint"/>
/// with the test discovery system, which the test execution engine uses to organize and schedule test execution.
/// </para>
/// <para>
/// Example usage:
/// <code>
/// [Test, ParallelGroup("DatabaseTests")]
/// public async Task DatabaseTest1()
/// {
/// // This test will run in parallel with other tests in the "DatabaseTests" group
/// }
///
/// [Test, ParallelGroup("DatabaseTests")]
/// public async Task DatabaseTest2()
/// {
/// // This will run in parallel with DatabaseTest1
/// }
///
/// [Test, ParallelGroup("UITests", Order = 1)]
/// public async Task UITest1()
/// {
/// // This test belongs to a different
/// }
/// </code>
/// </para>
/// </remarks>
public class ParallelGroupAttribute(string group) : TUnitAttribute, ITestDiscoveryEventReceiver
{
int IEventReceiver.Order => 0;

/// <inheritdoc />
public int Order { get; set; }

/// <summary>
/// Gets the name of the parallel group to which the test belongs.
/// </summary>
/// <remarks>
/// <para>
/// The group name is used to identify which tests should be executed in parallel with each other.
/// Tests decorated with <see cref="ParallelGroupAttribute"/> that have the same <see cref="Group"/> value
/// will be grouped together and executed concurrently, but isolated from tests in other groups.
/// </para>
/// <para>
/// Group names are case-sensitive string identifiers that should be chosen to represent a logical
/// set of tests that can safely run in parallel with each other. For example, "DatabaseTests",
/// "NetworkTests", or "UITests".
/// </para>
/// <para>
/// During test execution, the test engine organizes tests into groups based on this property, and
/// ensures that tests from different groups are not executed simultaneously, helping to manage
/// resource contention and test isolation.
/// </para>
/// <para>
/// This property is set via the constructor parameter and cannot be changed after the attribute
/// is instantiated.
/// </para>
/// </remarks>
/// <seealso cref="ParallelGroupConstraint"/>
/// <seealso cref="IParallelConstraint"/>
/// <seealso cref="NotInParallelAttribute"/>
public string Group { get; } = group;

/// <inheritdoc />
public void OnTestDiscovery(DiscoveredTestContext discoveredTestContext)
{
discoveredTestContext.SetParallelConstraint(new ParallelGroupConstraint(Group, Order));
Expand Down
49 changes: 49 additions & 0 deletions TUnit.Core/Attributes/ParallelLimiterAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,61 @@

namespace TUnit.Core;

/// <summary>
/// Limits the number of tests that can run in parallel for a test assembly, class, or method.
/// </summary>
/// <typeparam name="TParallelLimit">
/// The type that implements <see cref="IParallelLimit"/> and defines the maximum number
/// of tests that can execute concurrently.
/// </typeparam>
/// <remarks>
/// <para>
/// This attribute controls the degree of parallelism for test execution. When applied to a test assembly,
/// class, or method, it limits how many tests from that scope can run simultaneously.
/// </para>
/// <para>
/// The parallelism limit is defined by the <see cref="IParallelLimit.Limit"/> property of the
/// <typeparamref name="TParallelLimit"/> instance. This value is used to create a semaphore that
/// controls concurrent test execution.
/// </para>
/// <para>
/// Common implementations include:
/// <list type="bullet">
/// <item><description><c>DefaultParallelLimit</c> - Uses <see cref="Environment.ProcessorCount"/> as the limit</description></item>
/// <item><description>Custom implementations with fixed limits (e.g., <c>ParallelLimit3</c> with a limit of 3)</description></item>
/// </list>
/// </para>
/// <para>
/// Example usage:
/// <code>
/// // Apply to an assembly to limit all tests
/// [assembly: ParallelLimiter&lt;DefaultParallelLimit&gt;]
///
/// // Apply to a class to limit tests in that class
/// [ParallelLimiter&lt;ParallelLimit3&gt;]
/// public class MyTestClass
/// {
/// // Tests in this class will run with a maximum of 3 in parallel
/// }
///
/// // Apply to a specific test method
/// [Test]
/// [ParallelLimiter&lt;ParallelLimit1&gt;]
/// public void MyTest()
/// {
/// // This test will run exclusively (limit of 1)
/// }
/// </code>
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ParallelLimiterAttribute<TParallelLimit> : TUnitAttribute, ITestRegisteredEventReceiver
where TParallelLimit : IParallelLimit, new()
{
/// <inheritdoc />
public int Order => 0;

/// <inheritdoc />
public ValueTask OnTestRegistered(TestRegisteredContext testRegisteredContext)
{
testRegisteredContext.SetParallelLimiter(new TParallelLimit());
Expand Down
7 changes: 7 additions & 0 deletions TUnit.Core/Attributes/Tests/InheritsTestsAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
namespace TUnit.Core;

/// <summary>
/// Marks a class as inheriting test methods from its base classes.
/// </summary>
/// <remarks>
/// This attribute indicates to the TUnit test runner that test methods defined in base classes
/// should be considered part of the derived class's test suite.
/// </remarks>
[AttributeUsage(AttributeTargets.Class)]
public sealed class InheritsTestsAttribute : TUnitAttribute;
19 changes: 19 additions & 0 deletions TUnit.Core/Attributes/Tests/TestAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

namespace TUnit.Core;

/// <summary>
/// Marks a method as a test method in the TUnit testing framework.
/// </summary>
/// <remarks>
/// Methods marked with this attribute will be discovered and executed as tests during test runs.
/// The attribute automatically captures the file path and line number where the test is defined.
/// </remarks>
/// <example>
/// <code>
/// public class ExampleTests
/// {
/// [Test]
/// public void ExampleTest()
/// {
/// // Test code here
/// }
/// }
/// </code>
/// </example>
[AttributeUsage(AttributeTargets.Method)]
public sealed class TestAttribute(
[CallerFilePath] string file = "",
Expand Down
Loading