简体   繁体   中英

C# - Selenium - Retry Attribute not working with Selenium timeout

I have the following custom RetryAttribute taken from this post: NUnit retry dynamic attribute . It works fine but when I get a timeout error in Selenium it doesn´t work.

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
            wait.Until(ExpectedConditions.ElementToBeClickable(element));

Retry custom attribute:

/// <summary>
/// RetryDynamicAttribute may be applied to test case in order
/// to run it multiple times based on app setting.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class RetryDynamicAttribute : RetryAttribute {
    private const int DEFAULT_TRIES = 1;
    static Lazy<int> numberOfRetries = new Lazy<int>(() => {
        int count = 0;
        return int.TryParse(ConfigurationManager.AppSettings["retryTest"], out count) ? count : DEFAULT_TRIES;
    });

    public RetryDynamicAttribute() :
        base(numberOfRetries.Value) {
    }
}

And then apply the custom attribute.

[Test]
[RetryDynamic]
public void Test() {
    //.... 
}

How can this be solved?

Another solution would be to implement your own RetryAttribute to catch the WebDriver exception. This way you won't have to alter the test:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class RetryAttributeEx : PropertyAttribute, IWrapSetUpTearDown
{
    private int _count;

    public RetryAttributeEx(int count) : base(count) {
        _count = count;
    }

    public TestCommand Wrap(TestCommand command) {
        return new RetryCommand(command, _count);
    }

    public class RetryCommand : DelegatingTestCommand {

        private int _retryCount;

        public RetryCommand(TestCommand innerCommand, int retryCount)
            : base(innerCommand) {
            _retryCount = retryCount;
        }

        public override TestResult Execute(TestExecutionContext context) {

            for (int count = _retryCount; count-- > 0; ) {

                try {
                    context.CurrentResult = innerCommand.Execute(context);
                }
                catch (WebDriverTimeoutException ex) {
                    if (count == 0)
                      throw;

                    continue;
                }

                if (context.CurrentResult.ResultState.Status != ResultState.Failure.Status)
                    break;

                if (count > 0)
                    context.CurrentResult = context.CurrentTest.MakeTestResult();
            }

            return context.CurrentResult;
        }
    }

}

According to documentation here

NUnit Docs Retry Attribute

If a test has an unexpected exception, an error result is returned and it is not retried. Only assertion failures can trigger a retry . To convert an unexpected exception into an assertion failure, see the ThrowsConstraint .

emphasis mine.

The related ThrowsNothingConstraint simply asserts that the delegate does not throw an exception.

You need to catch the exception and cause a failed assertion if an exception was not expected.

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(5));
Assert.That(() => {
         wait.Until(ExpectedConditions.ElementToBeClickable(element));
     }, Throws.Nothing);

So the above code simply says execute the action and it should not expect an exception. If an exception is thrown then it is a failed assertion. The retry will execute if attribute is applied to the test.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM