MSTest 扩展(获取测试 class 实例)

MSTest Extending (Obtaining test class instance)

我有一些测试使用套接字连接来测试对服务器的调用。套接字对象是测试 class 本身中的一个全局变量,我在每次测试之前使用标有 [TestInitialize] 的方法设置它。我们称之为 TestInit()。

我想将 MSTest 扩展到 运行 每个测试两次,将套接字换出第二个 运行,让我能够有效地 运行 针对两个 [=28= 的测试].我通过扩展 TestMethodAttribute 的 Execute() 函数并调用 Invoke() 两次来做到这一点。

从 TestMethodAttribute 的 Execute() 来看,没有实例变量。我无法通过测试 class 来换出套接字。我的解决方案是使用静态变量来指示我们是否在第二次执行,如果是这样,TestInit() 使用第二个套接字而不是第一个。

问题: 我可以在扩展的 TestMethodAttribute 上使用锁来确保标记二次执行的静态变量不会与另一个测试发生竞争条件 运行 并联。问题是,正常的测试方法属性不会有线程锁定代码,因此将原始的 TestMethodAttribute 与扩展的混合会导致竞争条件。通过在 TestInit() 上线程锁定和在 TestCleanup() 上解锁来顺序锁定测试也不起作用,因为在我们设置 "secondary execution" 测试后,其他测试可以在第一次和第二次测试之间进入。 (竞争条件)。

有没有办法在 TestMethodAttribute 的 Execute() 中获取测试 class 实例?除了在任何地方强制使用自定义 TestMethodAttributes/TestClassAttributes 之外,我还能做些什么吗?请帮忙。

(不要建议我手动将交换写入测试,我的问题的全部意义在于让测试框架将其从您那里抽象出来。也不建议禁用并行化,因为我仍然需要它)。

谢谢。

您可以尝试使用 TestRunParameters 配置。这允许您在运行时将数据传递给您的测试。

<TestRunParameters>
  <Parmeter name="server1" value="https://s1.com"/>
  <Parmeter name="server2" value="https://s2.com"/>
</TestRunParameters>

您需要重构您的测试代码。

private testSomething(serverInfo)
{
  var socketConnection = getConnectionFromServerInfo(serverInfo);
  //use the socketConnection to perform tests
} 

现在实际的测试方法

[TestMethod]
public void TestSomethingOnS1
{
  testSomething(TestContext.Properties["server1"].ToString());
}

[TestMethod]
public void TestSomethingOnS2
{
  testSomething(TestContext.Properties["server2"].ToString());
}

more info

您可以使用 [ThreadStatic] 属性标记用于指示哪个 运行 的静态变量。

[TestClass]
public class MyTest
{
    [ThreadStatic]
    public static int Run = 1;

    [TestInitialize]
    public void TestInit()
    {
        if (Run == 1) 
        {
            //...
        }
        else if (Run == 2) 
        { 
            //...
        }
    }

    [MyTestMethod]
    public void MyTestMethod() 
    {
        //...
    }
}

public class MyTestMethodAttribute : TestMethodAttribute
{
    public override TestResult[] Execute(ITestMethod testMethod)
    {
        MyTest.Run = 1;
        var result1 = testMethod.Invoke(null);
        MyTest.Run = 2;
        var result2 = testMethod.Invoke(null);

        return new TestResult[] { result1, result2 };
    }
}