testfx icon indicating copy to clipboard operation
testfx copied to clipboard

Discuss whether `TestMethodAttribute.Execute` should return a single `TestResult` object

Open Youssef1313 opened this issue 9 months ago • 2 comments

TestMethodAttribute.Execute currently returns TestResult[] but all known implementations return a single result.

This seems to currently be an API flaw that has been present only for historical reasons where previously parameterized tests where handled in DataTestMethodAttribute:

https://github.com/microsoft/testfx/blob/50c26d1cfcd364cfc604797bdcc7cede1a8f92e0/src/TestFramework/MSTest.Core/Attributes/DataTestMethodAttribute.cs#L25-L35

So, DataTestMethodAttribute had to return multiple test results. The design is now very different and the whole DataTestMethodAttribute isn't actually required now. So I feel like the API should change here and return a single TestResult for simplicity.

Still, we need to be very careful with changes here, in case there are valid use cases for returning multiple results (but I don't see that right now).

Youssef1313 avatar Mar 24 '25 12:03 Youssef1313

One valid use case for this might be executing tests against multiple endpoints or in different environments (like Sql Server and MongoDB) for quick A/B testing, like so


[AttributeUsage(AttributeTargets.Method)]
public sealed class SplitTestAttribute : TestMethodAttribute
{
    public override TestResult[] Execute(ITestMethod testMethod)
    {
        ArgumentNullException.ThrowIfNull(testMethod);

        // Run test with default endpoint (A)
        TestClient.UseAlternativeUri = false;
        var resultA = base.Execute(testMethod);
        foreach (var r in resultA) r.DisplayName += " (A)";

        // Run test with alternative endpoint (B)
        var resultB = Array.Empty<TestResult>();
        TaskExecutor.RunSynchronously(async () =>
        {
            TestClient.UseAlternativeUri = true; // That is an AsyncLocal
            resultB = base.Execute(testMethod);
            foreach (var r in resultB) r.DisplayName += " (B)";
        });

        return resultA.Concat(resultB).ToArray();
    }
}


Obviously, this can be solved in other ways - probably those are even more cleanly or elegantly.

N-Olbert avatar Jun 04 '25 13:06 N-Olbert

Moving to 5.0.0, but we may cancel this change completely.

Youssef1313 avatar Jun 12 '25 18:06 Youssef1313

Cancelling.

Youssef1313 avatar Jun 24 '25 13:06 Youssef1313