MSTest/VSTest重试(重新运行)逻辑



遗憾的是,MStest/VStest 没有本地测试重新运行逻辑

我正在尝试实现这样一个自定义逻辑:

测试部分:

static int testNum = 1;
[TestMethod]
public void RerunTestOnce_Test()
{
testNum = testNum + 1;
Console.WriteLine("Test started");
Assert.IsTrue(testNum == 3, $"Test Failed with number {testNum}");
}

当testNum达到值3时,此测试应该第一次失败,第二次通过。

UP:这是一个模拟首次运行失败的合成示例。真正的测试是复杂的,有UI搜索方法和其他与系统和网络相关的工作,并且没有信心在大&长测试套件

有一个特殊的方法-重新运行TestOnce((,在TestCleanup:中调用

[TestCleanup]
public void TestCleanup()
{
TestHelper.RerunTestOnce(TestContext, this);
}

这里是测试助手类中RerunTestOnce的实现。在它中,使用反射&TestContext我们获取测试方法和初始化方法的名称,并再次运行它们:

public static void RerunTestOnce(TestContext testContext, object testInstance)
{
if (testContext.CurrentTestOutcome == UnitTestOutcome.Failed)
{
var type = testInstance.GetType();
if (type != null)
{
var testMethod = type.GetMethod(testContext.TestName);
var initMethod = type.GetMethods().SingleOrDefault(m=>m.CustomAttributes.SingleOrDefault(a=>a.AttributeType.Name == "TestInitializeAttribute")!= null);
var cleanupMethod = type.GetMethods().SingleOrDefault(m => m.CustomAttributes.SingleOrDefault(a => a.AttributeType.Name == "TestCleanupAttribute") != null);
Console.WriteLine($"[WARNING] Method [{testMethod}] was failed in first attempt. Trying to rerun...");
try
{
initMethod.Invoke(testInstance, null);
testMethod.Invoke(testInstance, null);
}
catch
{
Console.WriteLine($"[ERROR] Method [{testMethod}] was failed in second attempt. Rerun finished.");
}
}
}
}

一切都很好,在第二次尝试时,测试方法通过了,但最后我看到了失败的结果,并断言了第一次尝试的错误消息:

Test Failed - RerunTestOnce_Test
Message: Assert.IsTrue failed. Test Failed with number 2

MSTest如何以及何时创建测试结果-是否可以在第二次尝试后将测试结果更新为最后一次结果?

更新

今天我了解到,您实际上可以编写自己的TestMethod属性。

默认实现看起来像这个

public class TestMethodAttribute : Attribute
{
public virtual TestResult[] Execute(ITestMethod testMethod)
{
return new TestResult[1] { testMethod.Invoke(null) };
}
}

因此,您实际上可以创建自己的TestMethodWithRetry属性,并将其用于方法

[TestMethodWithRetry]
public void TestRetry()
{
var x = new Random().Next(0, 2);
Assert.AreEqual(1, x);
}
// or
[TestMethodWithRetry(Count = 10)]
public void TestRetry()
{
var x = new Random().Next(0, 2);
Assert.AreEqual(1, x);
}
// even works with DataRow
[TestMethodWithRetry(Count = 10)]
[DataRow(2)]
[DataRow(5)]
[DataRow(10)]
public void TestRetry(int max)
{
var x = new Random().Next(0, max);
Assert.AreEqual(1, x);
}
public class TestMethodWithRetryAttribute : TestMethodAttribute
{
public int Count { get; set; } = 1;
public override TestResult[] Execute(ITestMethod testMethod)
{
var count = Count;
TestResult[] result = null;
while (count > 0)
{
try
{
result = base.Execute(testMethod);
if (result[0].TestFailureException != null)
{
throw result[0].TestFailureException;
}
}
catch (Exception) when (count > 0)
{
}
finally
{
count--;
}
}
return result;
}
}

这只是一个简单的实现,但它似乎工作得出奇地好。


我提出了以下解决方案

public static void Retry(Action test, int retry = 10, int sleep = 0, [CallerMemberName] string testName = null)
{
int current = 1;
retry = Math.Max(1, Math.Min(retry, 10));
while (current <= retry)
{
try
{
test();
break;
}
catch (Exception ex) when (current < retry)
{
Debug.WriteLine("Test {0} failed ({1}. try): {2}", testName, current, ex);
}
if (sleep > 0)
{
Thread.Sleep(sleep);
}
current++;
}
}

使用

[TestMethod]
public void CanRollbackTransaction()
{
Helpers.Retry(() =>
{
var even = DateTime.Now.Second % 2 == 0;
Assert.IsTrue(even);
}, 3, 1000);
}

MSTest测试框架本身不支持本机测试重新运行逻辑
请考虑使用MSTestExMSTest测试框架的一组扩展,它确实支持测试重新运行逻辑:https://www.nuget.org/packages/MSTestEx/