// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
using System;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Commands;
namespace NUnit.Framework
{
///
/// Specifies that a test method should be rerun on failure up to the specified
/// maximum number of times.
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class RetryAttribute : NUnitAttribute, IRepeatTest
{
private readonly int _tryCount;
///
/// Construct a
///
/// The maximum number of times the test should be run if it fails
public RetryAttribute(int tryCount)
{
_tryCount = tryCount;
}
#region IRepeatTest Members
///
/// Wrap a command and return the result.
///
/// The command to be wrapped
/// The wrapped command
public TestCommand Wrap(TestCommand command)
{
return new RetryCommand(command, _tryCount);
}
#endregion
#region Nested RetryCommand Class
///
/// The test command for the
///
public class RetryCommand : DelegatingTestCommand
{
private readonly int _tryCount;
///
/// Initializes a new instance of the class.
///
/// The inner command.
/// The maximum number of repetitions
public RetryCommand(TestCommand innerCommand, int tryCount)
: base(innerCommand)
{
_tryCount = tryCount;
}
///
/// Runs the test, saving a TestResult in the supplied TestExecutionContext.
///
/// The context in which the test should run.
/// A TestResult
public override TestResult Execute(TestExecutionContext context)
{
int count = _tryCount;
while (count-- > 0)
{
try
{
context.CurrentResult = innerCommand.Execute(context);
}
// Commands are supposed to catch exceptions, but some don't
// and we want to look at restructuring the API in the future.
catch (Exception ex)
{
if (context.CurrentResult is null)
context.CurrentResult = context.CurrentTest.MakeTestResult();
context.CurrentResult.RecordException(ex);
}
if (context.CurrentResult.ResultState != ResultState.Failure)
break;
// Clear result for retry
if (count > 0)
{
context.CurrentResult = context.CurrentTest.MakeTestResult();
context.CurrentRepeatCount++; // increment Retry count for next iteration. will only happen if we are guaranteed another iteration
}
}
return context.CurrentResult;
}
}
#endregion
}
}