MsTest类的初始化和继承


74

我有一个用于测试的基类,它是通过以下方式组成的:

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

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

现在,我试图创建一个新的测试,该测试从基础继承并带有以下签名:

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

ClassInitialize永远不会被孩子所谓的测试...什么是真实的,正确的使用测试初始化与MSTest的继承方式?


Answers:


46

不幸的是,由于无法继承ClassInitializeAttribute类,因此无法通过这种方式实现。

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

尝试用另一种方法解决它。一种不太有效的方法是再次在ClassInitialize中定义方法,MyTest然后仅调用基本方法,而不是复制代码。


30
我尝试了您的方法,但该方法有效,但是老实说,Microsoft应该解决此问题,因为NUnit没有这种行为。
Raffaeu

当您说“不能继承ClassInitializeAttribute类”时,您是在说该类是sealed吗?—应该不会影响该属性在应用于继承方法时的显示方式…
binki 2015年

1
哦,我刚刚注意到这些方法static意味着它们不参与正常的继承。啊…
binki 2015年

1
您可以在给予好评这个UserVoice的功能在这里
伊曼Mahmoudinasab


8

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

using Microsoft.VisualStudio.TestTools.UnitTesting;

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

这也是我最终要做的,但是我很好奇。为什么要参加基础考试sealed?这是否会阻止您继承该类并完全按照您的计划去做?
保罗·尼尔森·贝克

我没有将它用于继承。我所有的真实测试类都来自不同的基类。此类仅用于AssemblyInitialize方法。这是我决定分开的设计决定。
戴夫·塞克斯顿

1

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


这不能代替[ClassInitialize]:加载整个程序集时将在没有上下文的情况下调用它。所以它并不比[AssemblyInitialize]
Marcel

0

更新:添加了锁,以避免多线程问题...

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

这可以帮助您不要忘记将初始化代码放在子类中。

不知道这种方法是否有任何缺点...

像这样:

public class TestBase
{
    private static bool _isInitialized = false;
    private object _locker = new object();

    public TestBase()
    {
        lock (_locker) 
        {
          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()
    {
    }
}

2
您没有使用此解决方案获得TestContext。真是可惜
Andy V

另外,您没有CleanUp
bubi

而且您通常不需要这些。对于适合的情况,这通常是一个很好的解决方案。
BWhite

这里的一个严重缺陷是线程安全性(或缺乏安全性)。由于所有测试将并行运行,因此它们都将在大约调用构造函数。同时,它们中的大多数将进入TestClassInitialize()方法,直到其中一个最终退出该方法并将_isInitialized设置为true。
Mladen B.19年

静态成员完全特定于声明类;子类不会获得单独的副本。
亚历克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.