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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/334515/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:44:25  来源:igfitidea点击:

Do you use TestInitialize or the test class constructor to prepare each test? and why?

.netunit-testingconstructor

提问by Anthony Mastrean

This question regards unit testing in Visual Studio using MSTest (this is important, because of MSTest's execution order). Both the method marked [TestInitialize] and the test class constructor will run before each test method.

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

So, the question is, what do you tend to do in each of these areas? Do you avoid performing certain activities in either? What is your reason: style, technical, superstition?

那么,问题是,您在每个领域都倾向于做什么?您是否避免在其中进行某些活动?你的理由是什么:风格、技术、迷信?

采纳答案by Anthony Mastrean

The constructor is just a structure provided by the language. Every test framework seems has its own controlled lifecycle "initialize". You'll probably only get into trouble using the constructor to mutate your locals.

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

MSTest:You get an entire new instance of the test class for every TestMethod. This might be the only case where it's ok to mutate your locals in the constructor, initializer, or test method and not affect the other test methods.

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:You only get one Establishand Becausefor all your assertions (It). So, don't mutate your locals in your assertions. And don't depend on mutations of locals in base contexts (if you use them).

MSpec:你只有一次Establish,并Because为所有的断言(It)。所以,不要在你的断言中改变你的本地人。并且不要依赖于基本上下文中本地变量的突变(如果您使用它们)。

[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;
}

回答by T. Webster

Here are some advantages I've found with TestInitialize.

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

  • Some environmental variables (e.g. TestContext) are not accessible until after the test class is instantiated.
  • Can require implementation with derived class by marking a base TestInitialize method abstract.
  • Can easily override a base TestInitialize method and determine whether to call the base impl before the derived impl, after, or at all. In contrast, if you derive a test class from a base test class, in the case of a parameterless constructor, the base ctor will be called whether you intended it to or not.
  • Its explicit definition makes the intentions clear, and complements the TestCleanup method. You might argue that you can create a destructorfor every constructor, but it's not guaranteed that MS Test will handle destructors as you'd expect.
  • 一些环境变量(例如 TestContext)在测试类被实例化之前是不可访问的。
  • 可以通过将基本 TestInitialize 方法标记为抽象来要求使用派生类实现。
  • 可以轻松覆盖基础 TestInitialize 方法并确定是在派生 impl 之前、之后还是根本不调用基础 impl。相反,如果您从基测试类派生测试类,在无参数构造函数的情况下,无论您是否有意,都将调用基构造函数。
  • 它的明确定义使意图清晰,并补充了 TestCleanup 方法。您可能会争辩说,您可以为每个构造函数创建一个析构函数,但不能保证 MS Test 会按照您的预期处理析构函数。

回答by Romi

The main advantage of using either TestInitialize() or ClassInitialize() rather than the test class instance or static constructors is its explicit nature. It clearly communicates that you are doing some setup prior to your tests. Doing this consistently should improve maintainability in the long run.

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

回答by Anthony Mastrean

I prefer to use the [TestInitialize]method to perform instantiation of the object being tested and it's parameters. I only perform work in the constructor if it is necessary to instantiate a testing base class (which is usually where I create or refresh repositories, etc). This helps me keep the test framework code and test code separate logically and physically.

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

回答by bacar

This question is also asked (later) at What's the difference between using the constructor in VS Testing framework vs. TestInitialize() attribute?

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

FWIW I assume by "class constructor" you mean the instance constructor(not the static constructor).

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

I believe the same question you are asking could equally be asked about the static constructor vs. ClassInitialize...

我相信关于静态构造函数与ClassInitialize 的问题同样可以问您所问的相同问题......

回答by Ohad Schneider

I say use the constructor unless you need TestContext.

我说除非你需要使用构造函数TestContext

  1. If you can keep things simple, why not. A constructor is simpler than a magical attribute.
  2. You can use readonlywhich is a big thing in test initialization where you want to prepare stuff for the tests that they're not supposed to change (ideally the stuff you prepare would be immutable too).
  1. 如果你能保持简单,为什么不呢。构造函数比魔法属性更简单。
  2. 您可以readonly在测试初始化​​中使用which is a big thing,您希望为测试准备不应更改的内容(理想情况下,您准备的内容也是不可变的)。

回答by sschoof

I know I late to the party, but with asyncthe is another reason (that does not existed when this question was ask) for [TestInitialize]. The allows you to do asyncoperations to setup (eg. load a file) which is not possible in the constructor:

我知道我参加聚会迟到了,但是还有async另一个原因(在提出这个问题时不存在)对于[TestInitialize]. 允许您执行async在构造函数中无法进行的设置操作(例如加载文件):

        private string approver;        

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

回答by Patrick Desjardins

The object you test doesn't need to be instantiated in the [TestInitialize] method. You can test the constructor of your object in a test method [Test].

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

Object in the [TestInitialize] can be to setup your persistance storage or to prepare value that the object tested will used in the tests.

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

回答by Jevgenij Kononov

I hope somebody still needs that. This is my solution, how to unit test class constructor. I am unit testing class service and throwing an exception if debuggingService is null.

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

DebuggingStepTests class constructor

DebuggingStepTests 类构造函数

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");
}

UnitTests looks like this

单元测试看起来像这样

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

    //Act

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

And actual result: enter image description here

和实际结果: 在此处输入图片说明

Hope this will be helpful for somebody

希望这对某人有帮助

回答by Teoman shipahi

It depends on the scenario. If you have a test class, and for some weird reason if you need to create instance of it on another test class, you will need to use constructor.

这取决于场景。如果您有一个测试类,并且出于某种奇怪的原因需要在另一个测试类上创建它的实例,则需要使用构造函数。

Otherwise test initialize more fits in the concept. Firstly, same reasons written above, second MS can introduce more features on that attribute and you will benefit them, with constructor you will stuck into it.

否则测试初始化​​更适合这个概念。首先,与上面写的相同的原因,第二个 MS 可以在该属性上引入更多功能,您将受益,使用构造函数您将陷入困境。