Skip to content

Commit d7f76c4

Browse files
Add Retry and Retry with RetryExceptions examples (#1099)
* Add Retry and Retry with RetryExceptions examples * Update to latest nunit alpha package * Add a note that RetryExceptions is only available from NUnit 4.5.0
1 parent 07bbbab commit d7f76c4

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

.github/workflows/build-process.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
- name: Setup .NET
8080
uses: actions/setup-dotnet@v5
8181
with:
82-
dotnet-version: 9.x
82+
dotnet-version: 10.x
8383
- name: Restore dependencies
8484
run: dotnet restore $SOLUTION_LOCATION
8585
- name: Build

docs/articles/nunit/writing-tests/attributes/retry.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
RetryAttribute is used on a test method to specify that it should be rerun if it fails, up to a maximum number of times.
44

5+
[!code-csharp[Retry](~/snippets/Snippets.NUnit/Attributes/RetryAttributeExamples.cs#Retry)]
6+
57
Notes:
68

79
1. The argument you specify is the total number of attempts and __not__ the number of retries after an initial failure.
810
So `[Retry(1)]` does nothing and should not be used.
9-
2. It is not currently possible to use `RetryAttribute` on a `TestFixture` or any other type of test suite. Only single
10-
tests may be repeated.
11-
3. If a test has an unexpected exception, an error result is returned and it is not retried. Only assertion failures can
12-
trigger a retry. To convert an unexpected exception into an assertion failure, see the
13-
[ThrowsConstraint](xref:throwsconstraint).
11+
2. It is not currently possible to use `RetryAttribute` on a `TestFixture` or any other type of test suite.
12+
Only single tests may be repeated.
13+
3. If a test has an unexpected exception, an error result is returned and it is not retried.
14+
15+
From NUnit 4.5.0 you can enable retry on an expected exception such as `TimeoutException`
16+
by setting the `RetryExceptions` property. The value of this property is an array of anticipated exceptions that should be retried.
17+
18+
[!code-csharp[RetryWithRetryExceptions](~/snippets/Snippets.NUnit/Attributes/RetryAttributeExamples.cs#RetryWithRetryExceptions)]
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Diagnostics;
2+
using System.Threading.Tasks;
3+
using NUnit.Framework;
4+
5+
namespace Snippets.NUnit;
6+
7+
public class RetryAttributeExamples
8+
{
9+
#region Retry
10+
[TestFixture]
11+
public sealed class RetryTests
12+
{
13+
private readonly Random _random = new(42);
14+
15+
[Test]
16+
[Retry(5)]
17+
public async Task OperationShouldPassIn1s()
18+
{
19+
var sw = Stopwatch.StartNew();
20+
string result = await ExpensiveOperation();
21+
sw.Stop();
22+
Assert.That(sw.ElapsedMilliseconds, Is.LessThan(1000), "Operation did not complete in time");
23+
Assert.That(result, Is.Not.Null);
24+
}
25+
26+
private async Task<string> ExpensiveOperation()
27+
{
28+
// Simulate an expensive operation
29+
int duration = _random.Next(500, 1500);
30+
await Task.Delay(duration); // Simulate work
31+
return "Actual Result"; // Simulate a response
32+
}
33+
}
34+
#endregion
35+
36+
#region RetryWithRetryExceptions
37+
[TestFixture]
38+
public sealed class Retry
39+
{
40+
private int _delayInMilliseconds;
41+
42+
[OneTimeSetUp]
43+
public void Setup()
44+
{
45+
_delayInMilliseconds = 2500;
46+
}
47+
48+
[Test]
49+
[Retry(5, RetryExceptions = [typeof(OperationCanceledException)])]
50+
[CancelAfter(2000)]
51+
public async Task QueryServiceAsync(CancellationToken cancellationToken)
52+
{
53+
string result = await CallExternalServiceAsync(cancellationToken);
54+
Assert.That(result, Is.Not.Null);
55+
}
56+
57+
private async Task<string> CallExternalServiceAsync(CancellationToken cancellationToken)
58+
{
59+
// Call an external service that may time out
60+
int delayInMilliseconds = _delayInMilliseconds;
61+
if (_delayInMilliseconds > 1000)
62+
_delayInMilliseconds -= 1000; // Decrease delay for next attempt
63+
64+
await Task.Delay(delayInMilliseconds, cancellationToken); // Simulate a delay that may exceed
65+
return "Actual Result"; // Simulate a response
66+
}
67+
}
68+
#endregion
69+
}

docs/snippets/Snippets.NUnit/Snippets.NUnit.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<ItemGroup>
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
13-
<PackageReference Include="NUnit" Version="4.4.0" />
13+
<PackageReference Include="NUnit" Version="4.5.0-alpha.0.17" />
1414
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0" />
1515
<PackageReference Include="NUnit.Analyzers" Version="4.11.2">
1616
<PrivateAssets>all</PrivateAssets>

0 commit comments

Comments
 (0)