您是否使用 TestInitialize 或测试类构造函数来准备每个测试? 为什么?

这个问题涉及到在 Visual Studio 中使用 MSTest 进行单元测试(这一点很重要,因为 MSTest 是 执行令)。标记为[ TestInitialize ]的方法和测试类构造函数都将在每个测试方法之前运行。

所以,问题是,你倾向于在这些领域做什么?你是否避免在任何一种情况下进行某些活动?你的理由是什么: 风格,技术,迷信?

57187 次浏览

您测试的对象不需要在[ TestInitialize ]方法中实例化。可以在测试方法[ Test ]中测试对象的构造函数。

[ TestInitialize ]中的对象可以是设置持久性存储或准备测试对象将在测试中使用的值。

我更喜欢使用 [TestInitialize]方法来执行被测对象及其参数的实例化。只有在需要实例化测试基类(通常是创建或刷新存储库等)时,我才在构造函数中执行工作。这有助于我在逻辑上和物理上将测试框架代码和测试代码分开。

这个问题(稍后)也会在 在 VS 测试框架中使用构造函数与在 TestInitialize ()属性中使用构造函数有什么区别?上提出

FWIW 我假设“类构造函数”指的是 实例构造函数实例构造函数(不是 静态构造函数静态构造函数)。

我相信同样的问题,你正在问同样可以问关于静态构造函数与 初始化课程..。

使用 TestInitialize ()或 ClassInitialize ()而不是测试类实例或静态构造函数的主要优点是它的显式特性。它清楚地表明您正在测试之前进行一些设置。从长远来看,坚持这样做应该会提高可维护性。

构造函数只是语言提供的一个结构。每个测试框架似乎都有自己的受控生命周期“初始化”。使用构造函数来变异本地变量可能只会遇到麻烦。

MSTest: 对于每个 TestMethod,您将获得测试类的一个完整的新实例。这可能是唯一可以在构造函数、初始值设定项或测试方法中变更局部变量而不影响其他测试方法的情况。

public class TestsForWhatever
{
public TestsForWhatever()
{
// You get one of these per test method, yay!
}


[TestInitialize]
public void Initialize()
{
// and one of these too!
}


[TestMethod]
public void AssertItDoesSomething() { }


[TestMethod]
public void AssertItDoesSomethingElse() { }
}

MSpec: 对于所有断言(It) ,您只能得到一个 EstablishBecause。所以,不要在你的断言中改变你的当地人。并且不要依赖于基本上下文中的局部变量(如果使用它们的话)。

[Subject(typeof(Whatever))]
public class When_doing_whatever
{
Establish context = () =>
{
// one of these for all your Its
};


Because of = () => _subject.DoWhatever();


It should_do_something;
It should_do_something_else;
}

以下是我在 TestInitialize 中发现的一些优势。

  • 一些环境变量(例如 TestContext)在测试类被实例化之后才能被访问。
  • 可以通过标记基 TestInitialize 方法抽象来要求使用派生类实现。
  • 可以轻松地重写基 TestInitialize 方法,并确定是在派生的 impl 之前、之后还是根本不调用基 impl。相反,如果从基测试类派生测试类,在无参数构造函数的情况下,将调用基 ctor,无论您是否希望这样做。
  • 它的明确定义使意图清晰,并补充了 TestCleanup 方法。您可能会争辩说,您可以为每个构造函数创建一个 毁灭者,但是不能保证 MS Test 会像您期望的那样处理析构函数。

这取决于具体情况。如果您有一个测试类,出于某种奇怪的原因,如果您需要在另一个测试类上创建它的实例,那么您将需要使用构造函数。

否则,测试初始化更符合这个概念。首先,同样的原因写在上面,第二个 MS 可以引入更多的功能,这个属性,你将受益于他们,与构造器你将坚持它。

我建议使用构造函数,除非您需要 TestContext

  1. 如果你能让事情保持简单,为什么不呢。构造函数比魔法属性简单。
  2. 您可以使用 readonly,这是测试初始化中的一件大事,您希望为测试准备不应该更改的内容(理想情况下,您准备的内容也是不可变的)。

对于 async,还有另一个原因(当问到这个问题时并不存在)。它允许您执行 async操作来设置(例如加载文件) ,这在构造函数中是不可能的:

        private string approver;


[TestInitialize]
public async Task Initialize()
{
approver = await File.ReadAllTextAsync("approver.json");
}

我希望有人仍然需要它。这是我的解决方案,如何单元测试类构造函数。 我正在对类服务进行单元测试,如果 debuggingService 为 null,则抛出一个异常。

类构造函数

private readonly IDebuggingService debuggingService;


public string StepName { get; set; }


public DebuggingStep(IDebuggingService _debuggingService)
{
_log.Starting();
StepName = "DebuggingStep";


debuggingService = _debuggingService
?? throw new ArgumentException("DebuggingStep init failure due to => IDebuggingService null");
}

单元测试看起来像这样

    [Fact]
public void TestDebuggingStepConstructorWhen_InitServiceIsNull_ResultArgumentException()
{
//Arrange
var arrange = new Action(() =>
{
new DebuggingStep(null);
});


//Act


//Arrange
Assert.Throws<ArgumentException>(arrange);
}

实际结果是: enter image description here

希望这对某些人有帮助