简体   繁体   English

如何将测试数据传递给 [TearDown] 之类的 NUnit 挂钩

[英]How to pass Test data to NUnit hooks like [TearDown]

I have a testing framework that has been converted to heavily utilize NUnit [Parallelizable] .我有一个已转换为大量使用 NUnit [Parallelizable]的测试框架。 I used to store contextual test data in the base class of the [TestFixture] which NUnit orchestrates the hooks like [OneTimeSetUp] , [TearDown] , etc.我曾经将上下文测试数据存储在[TestFixture]的基础 class 中,NUnit 编排了[OneTimeSetUp][TearDown]等钩子。

For example:例如:

[Test]
public void GoToGoogle()
{
    var driver = new ChromeDriver();

    // do some stuff

    // Would like to pass data outside of test scope
    TestContext.CurrentContext.Test.Properties.Set("DriverUrl", driver.Url); // Obviously does not work

    Assert.Fail("This test should fail");
}

In the [TearDown] hook, I would like to get certain information about the test contextually.[TearDown]挂钩中,我想根据上下文获取有关测试的某些信息。 Because not everything is able to be handled nicely in asserts.因为并不是所有的事情都能在断言中得到很好的处理。

[TearDown]
public void TearDown()
{
    var url = TestContext.CurrentContext.Test.Properties["DriverUrl"].ToString();
    var msg = $"Test encountered an error at URL: {url}"
    TestAPI.PushResult(Result.Fail, msg);
}

The code above involving the TestContext does not work for obvious reasons, but I am wondering if there is a best practice that allows for me to pass data in this manner, keeping in mind respect to [Parallelizable] and that I cannot scope test data or dependencies to the [TestFixture]上面涉及 TestContext 的代码由于明显的原因不起作用,但我想知道是否有允许我以这种方式传递数据的最佳实践,请记住尊重[Parallelizable]并且我不能 scope 测试数据或对[TestFixture]的依赖

You say "for obvious reasons" but I'll first spell out the reasons why you cannot effectively set a property on the current test through TestContext .你说“出于明显的原因”,但我会首先阐明你不能通过TestContext在当前测试上有效设置属性的原因。 After all, other people just might be reading this.毕竟,其他人可能正在阅读本文。 :-) :-)

The Obvious Part明显的部分

TestContext.CurrentContext.Test does not return the internal representation of a test from inside NUnit. TestContext.CurrentContext.Test不从 NUnit 内部返回测试的内部表示。 Doing so would allow users to break NUnit in a variety of ways.这样做将允许用户以多种方式破坏 NUnit。 In particular, TestContext.CurrentContext.Test.Properties returns a copy of the properties used within NUnit.特别是, TestContext.CurrentContext.Test.Properties返回 NUnit 中使用的属性的副本。

That copy of the properties is not readonly , so you are able to set properties on it.该属性的副本不是readonly的,因此您可以在其上设置属性。 For that reason, one might expect to be able to set it in the [Test] method and access the value in the [Teardown] .出于这个原因,人们可能希望能够在[Test]方法中设置它并访问[Teardown]中的值。

Unfortunately, because of a minor implementation detail, that's not the case.不幸的是,由于一个小的实现细节,情况并非如此。 In fact, each time you use TestContext.CurrentContext , an entirely new copy of the context is created.事实上,每次您使用TestContext.CurrentContext时,都会创建一个全新的上下文副本。 The only reason for this, I'm afraid, is that it was originally implemented that way and is a bit difficult to change in a non-breaking way.恐怕唯一的原因是它最初是以这种方式实现的,并且很难以不间断的方式进行更改。

As a result of this implementation detail, we lost an easy way for the three parts (SetUp, Test method, TearDown) of a test to communicate.由于这个实现细节,我们失去了测试的三个部分(设置、测试方法、拆卸)进行通信的简单方法。 Prior to the availability of parallel execution, it was possible to pass such information using members of the fixture class. That no longer works once tests are run in parallel.在并行执行可用之前,可以使用夹具 class 的成员传递此类信息。一旦测试并行运行,这将不再有效。

Workarounds解决方法

  1. Use Thread Local Storage to hold the retained information.使用 Thread Local Storage 来保存保留的信息。 SetUp, Test and Teardown all run on the same thread. SetUp、Test 和 Teardown 都在同一个线程上运行。 Note that OneTimeSetUp and OneTimeTearDown will not generally use the same thread in a parallel execution environment.请注意,OneTimeSetUp 和 OneTimeTearDown 在并行执行环境中通常不会使用相同的线程。

  2. If you are wiling to run fixtures in parallel but not individual test cases, then you can still use class members to retain information.如果您愿意并行运行固定装置而不是单独的测试用例,那么您仍然可以使用 class 成员来保留信息。 As a further step, apply the SingleThreadedAttribute to your fixture, forcing all the code associated with it (including one-time setup and teardown) to run on the same thread.作为进一步的步骤,将SingleThreadedAttribute应用于您的装置,强制与其关联的所有代码(包括一次性设置和拆卸)在同一线程上运行。

If you have many fixtures, which can run in parallel, the second approach may actually give you a better performance trade-off than other approaches.如果您有许多可以并行运行的固定装置,则第二种方法实际上可能比其他方法给您带来更好的性能权衡。 Unfortunately, not everyone can use it - at least not without a major reorganization of their tests.不幸的是,并不是每个人都可以使用它——至少在他们的测试没有进行重大重组的情况下是不行的。 You have to look at what your own tests are doing.你必须看看你自己的测试在做什么。

Permanent Solution永久解决方案

That would be to modify NUnit so that properties are both writable and shareable, at least within a single fixture instance.那将是修改 NUnit,使属性既可写又可共享,至少在单个夹具实例中是这样。 There have already been a few feature requests out there to do that on the NUnit GitHub project.在 NUnit GitHub 项目上已经有一些功能请求可以做到这一点。 I'm no longer active on the framework project, so I don't know what the plans are.我不再积极参与框架项目,所以我不知道计划是什么。 However, I think I can say that it's not likely to happen before a major version change, ie NUnit 4.0.但是,我想我可以说这不太可能在主要版本更改(即 NUnit 4.0)之前发生。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM