MsTest ClassInitialize和Inheritance

时间:2013-04-11 08:54:40

标签: c# mstest

我有一个测试的基类,它由以下方式组成:

[TestClass]
public abstract class MyBaseTest
{
   protected static string myField = "";

   [ClassInitialize]
   public static void ClassInitialize(TestContext context)
   {
       // static field initialization
       myField = "new value";
   }
}

现在我正在尝试使用以下签名创建一个继承自base的新测试:

[TestClass]
public class MyTest : MyBaseTest
{
   [TestMethod]
   public void BaseMethod_ShouldHave_FieldInitialized()
   {
       Assert.IsTrue(myField == "new value");
   }
}

子测试永远不会调用ClassInitialize ...在MsTest上使用带继承的测试初始化​​的真实且正确的方法是什么?

5 个答案:

答案 0 :(得分:35)

不幸的是,你不能这样做,因为ClassInitializeAttribute Class不能被继承。

继承的属性可以由使用它的类的子类使用。由于ClassInitializeAttribute无法继承,因此在初始化MyTest类时,无法调用ClassInitialize类中的MyBaseTest方法。

尝试用另一种方式解决它。一种效率较低的方法是再次定义ClassInitialize中的MyTest方法,只调用基本方法而不是复制代码。

答案 1 :(得分:5)

可能的解决方法是使用AssemblyInitializeAttribute来定义新类。它显然有不同的范围,但对我来说它满足了我的需求(横切关注点,恰好需要对每个测试类和测试方法都设置完全相同的设置。)

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MyTests
{
  [TestClass]
  public sealed class TestAssemblyInitialize
  {
    [AssemblyInitialize]
    public static void Initialize(TestContext context)
    {
      ...
    }
  }
}

答案 2 :(得分:1)

我们知道,当类运行时,为类中的每个[TestMethod]构造一个新的类实例。每次发生这种情况时,都会调用基类的无参数构造函数。难道你不能简单地在基类中创建一个静态变量并在构造函数运行时测试它吗?

这有助于您不要忘记将初始化代码放在子类中。

不确定此方法是否有任何缺点......

像这样:

public class TestBase
{
    private static bool _isInitialized = false;
    public TestBase()
    {
        if (!_isInitialized)
        {
            TestClassInitialize();
            _isInitialized = true;
        }
    }

    public void TestClassInitialize()
    {
        // Do one-time init stuff
    }
}
public class SalesOrderTotals_Test : TestBase
{
    [TestMethod]
    public void TotalsCalulateWhenThereIsNoSalesTax()
    {
    }
    [TestMethod]
    public void TotalsCalulateWhenThereIsSalesTax()
    {
    }
}

答案 3 :(得分:0)

在基类上使用静态构造函数?根据设计,它仅执行一次,并且对继承没有怪异的限制,例如ClassInitializeAttribute。

答案 4 :(得分:0)

对于只是想让基本的ClassInit正常工作并在这里结束的任何人。

这是您的测试类外观的一个示例。

// Note: intentionally returns integers below 1,000 unchanged.
// For true precision across all numbers, remove the first line.
function siRound(n, precision=3) {
    if (x<1e3) return x+''
    let tier = Math.log10(x)/3 | 0
    let str = (x / 10**(tier*3)).toPrecision(precision)
    if (str>=1e3) str = (x / 10**(++tier*3)).toPrecision(precision)
    return str + (['','k','M','G','T','P','E','Z','Y'])[tier]
}

您最终在ClassInitialize和ClassCleanup中调用的静态方法可以在任何地方,并且可以命名为任何东西。