Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce RetryAttribute for test methods #4586

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Youssef1313
Copy link
Member

Fixes #3161

/// <summary>
/// Gets the number of retries that the test should make in case of failures.
/// </summary>
public int MaxRetries { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about MaxRetryAttempts?

/// <summary>
/// Initializes a new instance of the <see cref="RetryAttribute"/> class with the given number of max retries.
/// </summary>
public RetryAttribute(int maxRetries)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to build something too complex but I think it would be good to have:

  • Delay: wait time between 2 retries
  • optional: some backoff strategy, I think constant and exponential are the most used.

/// This attribute is used to set a retry count on a test method in case of failure.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class RetryAttribute : Attribute
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to have this attribute non-sealed so we allow extensibility, which means the logic should also be partially here so it can be overrided. I mainly want that so people (or we?) could ship a retry based off Polly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we have a precedens for that with data sources that don't use non-sealed class, but rather than that an interface (ITestDataSource) on the attribute, so any implementer does not have to provide the same ctor parameters we provided.

/// Initializes a new instance of the <see cref="RetryAttribute"/> class with the given number of max retries.
/// </summary>
public RetryAttribute(int maxRetries)
=> MaxRetries = maxRetries;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we validate value here?

/// <summary>
/// Gets the number of retries that the test should make in case of failures.
/// </summary>
public int MaxRetries { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's be explicit here this is in addition to the original call so a value of 1 means call + 1 retry, so 2 attempts in total.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strong opinion, but the comment already says "in case of failure", to me it is clear.

/// </summary>
/// <returns>
/// The number of retries, which is always greater than or equal to 1.
/// If RetryAttribute is not present, returns 1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it's how you interpret language, but in TUnit, lack of a retry attribute means a retry count of 0;

Because if I do [Retry(1)] I'd expect it to try again after a failure, once.

If I'm reading this PR correctly, [Retry(1)] currently means, run the test normally as you would and never retry? So that's retrying 0 times.

Does that make sense? The number doesn't work with the wording. This usage would work better with [Attempt(1)] or [Try(1)] or something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thomhurst Yup indeed. I'll be working on a fix so that [Retry(n)] means it can run 1 + n times at max (normal first attempt + n retries).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, NUnit imho does it the way when Retry(1) means normal run, and I only see that being source of confusion.

@nohwnd
Copy link
Member

nohwnd commented Jan 9, 2025

FYI From previous talks with Playwright where they have good retries, that imho were attempted to be duplicated in mstest.playwright, Max also mentioned that they wanted:

  • max retries to be configurable via config
  • see what max retries value is in assembly initialize (might be specific to them because they are in position of test framework in vstest, so that story might not be relevant here, where they have way more power via extensions easily)
  • have good reporting of the retries, to be able to show retries that were not passing

@Youssef1313
Copy link
Member Author

Youssef1313 commented Jan 9, 2025

max retries to be configurable via config

Not sure what shape would you be expecting. Currently, every application of the attribute is specifying the number of retries


see what max retries value is in assembly initialize (might be specific to them because they are in position of test framework in vstest, so that story might not be relevant here, where they have way more power via extensions easily)

This is currently info specific to the test method itself and is irrelevant to assembly initialize. I think you are talking of a completely different design that allows a "global" retry count, not a Retry attribute on test methods which I'm implementing here.


have good reporting of the retries, to be able to show retries that were not passing

We are going to have a design that allows that, but that is unlikely to be implemented in this PR though, unfortunately. We need to know better how to communicate that information to tools that will make use of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Develop Retry Attribute for TestMethod
4 participants