|
87 | 87 | <h1 id="retry">Retry</h1> |
88 | 88 |
|
89 | 89 | <p>RetryAttribute is used on a test method to specify that it should be rerun if it fails, up to a maximum number of times.</p> |
| 90 | +<pre><code class="lang-csharp" name="Retry">[TestFixture] |
| 91 | +public sealed class RetryTests |
| 92 | +{ |
| 93 | + private readonly Random _random = new(42); |
| 94 | + |
| 95 | + [Test] |
| 96 | + [Retry(5)] |
| 97 | + public async Task OperationShouldPassIn1s() |
| 98 | + { |
| 99 | + var sw = Stopwatch.StartNew(); |
| 100 | + string result = await ExpensiveOperation(); |
| 101 | + sw.Stop(); |
| 102 | + Assert.That(sw.ElapsedMilliseconds, Is.LessThan(1000), "Operation did not complete in time"); |
| 103 | + Assert.That(result, Is.Not.Null); |
| 104 | + } |
| 105 | + |
| 106 | + private async Task<string> ExpensiveOperation() |
| 107 | + { |
| 108 | + // Simulate an expensive operation |
| 109 | + int duration = _random.Next(500, 1500); |
| 110 | + await Task.Delay(duration); // Simulate work |
| 111 | + return "Actual Result"; // Simulate a response |
| 112 | + } |
| 113 | +} |
| 114 | +</code></pre> |
90 | 115 | <p>Notes:</p> |
91 | 116 | <ol> |
92 | | -<li>The argument you specify is the total number of attempts and <strong>not</strong> the number of retries after an initial failure. |
93 | | -So <code>[Retry(1)]</code> does nothing and should not be used.</li> |
94 | | -<li>It is not currently possible to use <code>RetryAttribute</code> on a <code>TestFixture</code> or any other type of test suite. Only single |
95 | | -tests may be repeated.</li> |
96 | | -<li>If a test has an unexpected exception, an error result is returned and it is not retried. Only assertion failures can |
97 | | -trigger a retry. To convert an unexpected exception into an assertion failure, see the |
98 | | -<a class="xref" href="../constraints/ThrowsConstraint.html">ThrowsConstraint</a>.</li> |
| 117 | +<li><p>The argument you specify is the total number of attempts and <strong>not</strong> the number of retries after an initial failure. |
| 118 | +So <code>[Retry(1)]</code> does nothing and should not be used.</p> |
| 119 | +</li> |
| 120 | +<li><p>It is not currently possible to use <code>RetryAttribute</code> on a <code>TestFixture</code> or any other type of test suite. |
| 121 | +Only single tests may be repeated.</p> |
| 122 | +</li> |
| 123 | +<li><p>If a test has an unexpected exception, an error result is returned and it is not retried.</p> |
| 124 | +<p>From NUnit 4.5.0 you can enable retry on an expected exception such as <code>TimeoutException</code> |
| 125 | +by setting the <code>RetryExceptions</code> property. The value of this property is an array of anticipated exceptions that should be retried.</p> |
| 126 | +</li> |
99 | 127 | </ol> |
| 128 | +<pre><code class="lang-csharp" name="RetryWithRetryExceptions">[TestFixture] |
| 129 | +public sealed class Retry |
| 130 | +{ |
| 131 | + private int _delayInMilliseconds; |
| 132 | + |
| 133 | + [OneTimeSetUp] |
| 134 | + public void Setup() |
| 135 | + { |
| 136 | + _delayInMilliseconds = 2500; |
| 137 | + } |
| 138 | + |
| 139 | + [Test] |
| 140 | + [Retry(5, RetryExceptions = [typeof(OperationCanceledException)])] |
| 141 | + [CancelAfter(2000)] |
| 142 | + public async Task QueryServiceAsync(CancellationToken cancellationToken) |
| 143 | + { |
| 144 | + string result = await CallExternalServiceAsync(cancellationToken); |
| 145 | + Assert.That(result, Is.Not.Null); |
| 146 | + } |
| 147 | + |
| 148 | + private async Task<string> CallExternalServiceAsync(CancellationToken cancellationToken) |
| 149 | + { |
| 150 | + // Call an external service that may time out |
| 151 | + int delayInMilliseconds = _delayInMilliseconds; |
| 152 | + if (_delayInMilliseconds > 1000) |
| 153 | + _delayInMilliseconds -= 1000; // Decrease delay for next attempt |
100 | 154 |
|
| 155 | + await Task.Delay(delayInMilliseconds, cancellationToken); // Simulate a delay that may exceed |
| 156 | + return "Actual Result"; // Simulate a response |
| 157 | + } |
| 158 | +} |
| 159 | +</code></pre> |
101 | 160 | </article> |
102 | 161 | </div> |
103 | 162 |
|
|
0 commit comments