初始化和继承

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

[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 上使用带继承的测试初始化的 真实而正确方法是什么?

42250 次浏览

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

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

试着用另一种方法解决它。一种效率较低的方法是在 MyTest中重新定义 ClassInitialize方法,只调用基方法,而不是复制代码。

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

我们知道类的新实例在运行时为类中的每个[ 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()
{
}
}

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

using Microsoft.VisualStudio.TestTools.UnitTesting;


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

在基类上使用静态构造函数?根据设计,它只执行一次,而且它没有像 ClassInitializeAttribute 那样对继承有奇怪的限制。

ClassInitialize 和 ClassCleanup 属性有一个参数:

[ClassInitialize(InheritanceBehavior.BeforeEachDerivedClass)]
public static void ClassInitialize(TestContext context)
{
// gets called once for each class derived from this class
// on initialization
}


[ClassCleanup(InheritanceBehavior.BeforeEachDerivedClass)]
public static void Cleanup()
{
// gets called once for each class derived from this class
// on cleanup
}

你想怎么做就怎么做。