Nunit: 新克隆后 nunit.framework.tests 中的单元测试失败

创建于 2018-06-25  ·  31评论  ·  资料来源: nunit/nunit

我刚刚获取了一个新的 nunit 克隆,并在 Visual Studio 2017(社区 15.7.4)中使用最新的 NUnit 3 测试适配器(3.10 并行运行测试)在 Windows 10 Professional 上打开了解决方案,并选择了“Debug-AnyCPU "并点击构建。

阅读 BUILDING.md 后,我似乎应该忽略任何不是来自 nunit.framework.tests-* 和 nunitlite.tests-* 的失败

然而,一开始我从 nunit.framework.tests-* 得到 2 个失败

第一个错误:

Test Name:  TestCaseSourceCanAccessWorkDirectory("C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20")
Test FullName:  NUnit.Framework.TestContextTests.TestCaseSourceCanAccessWorkDirectory("C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20")
Test Source:    C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\TestContextTests.cs : line 110
Test Outcome:   Failed
Test Duration:  0:00:00.001

Result StackTrace:  at NUnit.Framework.TestContextTests.TestCaseSourceCanAccessWorkDirectory(String workDirectory) in C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\TestContextTests.cs:line 112
Result Message: 
Expected string length 34 but was 50. Strings differ at index 34.
  Expected: "C:\\Users\\ace.olszowka\\source\\nunit"
  But was:  "C:\\Users\\ace.olszowka\\source\\nunit\\bin\\Debug\\net20"
  -------------------------------------------------^

查看来源我不明白这是怎么可能的,据我所知,这些值应该是相同的( _workDirectory和测试数据都设置为TestContext.CurrentContext.WorkDirectory )我唯一的猜测是某种类型的竞争条件,可能是由于我的配置不当?

第二个错误:

Test Name:  StackTracesAreFiltered("WarningInBeginInvoke",4)
Test FullName:  NUnit.Framework.Assertions.WarningTests.StackTracesAreFiltered("WarningInBeginInvoke",4)
Test Source:    C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\Assertions\WarningTests.cs : line 292
Test Outcome:   Failed
Test Duration:  0:00:00.004

Result StackTrace:  at NUnit.Framework.Assertions.WarningTests.StackTracesAreFiltered(String methodName, Int32 maxLineCount) in C:\Users\ace.olszowka\source\nunit\src\NUnitFramework\tests\Assertions\WarningTests.cs:line 310
Result Message: 
Multiple failures or warnings in test:
  1) (Warning message)
  2) Expected the number of lines to be no more than 4, but it was 5:

 1. at NUnit.TestData.WarningFixture.<>c__DisplayClass45_0.<WarningInBeginInvoke>b__0()
 2. at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
 3. at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)
 4. at System.Runtime.Remoting.Proxies.AgileAsyncWorkerItem.ThreadPoolCallBack(Object o)
 5. at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
(end)

我迷失在这个测试试图在这里做的事情中; 但根据我有限的理解,这段代码似乎对调用堆栈中的任何更改非常敏感,这可能是由于 .NET Framework 中最近的更改吗?

我还发现 NUnitLite.Tests.CommandLineTests 中的每个测试用例都失败了,如果这是意外,我很乐意在那里挖掘。

看到构建在 CI 中传递,这些可能只是我的配置问题,但在 BUILDING.md 中没有提到关于此的任何内容,因此认为报告值得。

bug normal

所有31条评论

感谢报告! 我已经确认TestCaseSourceCanAccessWorkDirectoryCommandLineTests在测试资源管理器中不起作用。 我们需要想出一种方法让它们独立于 runner 和并行性。 @nunit/framework-team 有什么想法吗?

对于第二个错误,这是一个气味测试。 将其提高到 5 是有道理的。

过去,我只是告诉人们不要将测试资源管理器用于 NUnit 测试。 其他团队成员反对这种说法,即测试资源管理器已成为许多人运行测试的默认方式。

对于特定的运行器在测试测试框架时没有用,肯定有充分的先例。 被测测试框架是一种非常特殊的情况,大多数用户都不会遇到。 OTOH,如果团队愿意,也许您会将能够通过适配器在测试浏览器下成功运行作为目标。

不管你做什么,我认为你应该发布一些文档,告诉人们在测试浏览器下运行 NUnit 测试目前不起作用。 在这种情况下,您可以告诉他们这是实现目标的目标,也可以不是优先事项,以决定者为准。

作为适配器的第一作者和框架的多年贡献者,我一直谴责在 NUnit 开发中使用测试资源管理器。 这仍然是我对这个问题的看法。 哎呀,我什至不喜欢我们现在使用控制台来测试我们 CI 中的框架!!!

无论做出什么决定,我认为当出现可能是也可能不是由于适配器引起的问题时,您将不得不继续将人们送回实际的 NUnit 运行程序(NUnitLite 或控制台运行程序)。 即使它在 NUnit 项目下,适配器仍然基本上等同于第三方运行器。

FWIW 从外面看:只要有文件记录,它以哪种方式切割对我来说真的无关紧要。

开箱即用,作为开发人员,当我遇到任何使用我在内部使用的相同实践的新项目时,我会尝试做我通常会做的事情:

  1. 克隆代码
  2. 阅读 README.md/BUILD.md/HACKING.md
  3. 尝试构建(无更改)
  4. 运行单元测试(通过集成的 Runner)。
  5. 如果一切正常,就开始玩东西。

在过去,这本来是 ReSharper 的 dotCover,但我们一直试图摆脱它,因为当有免费/开源软件替代品“主要工作”时,许可成本对于小商店/个人开发人员来说简直是疯狂。

集成开发环境的概念有很多(在我看来),不必跳出工作流是非常有用的,这就是我们这样做的原因。

但是,如果我们希望使用我认为没问题的 Console Runner(或其他一些 Runner),只需将其记录下来。

如果你在 NUnit 上开发,在框架上工作,我认为混合任何以特殊方式做事的运行程序(R#,我们自己的适配器)可能会混淆这个问题。 我想知道该框架在与运行程序一起测试之前是否可以单独正常工作。 所以在我自己的工作中,我在开发时使用 nunitlite 进行测试,然后在本地运行 CI。 如果一个人想在测试资源管理器中在 NUnit 上进行开发,我会说他们仍然应该在本地运行 CI,并且在任何事情看起来不可靠时也应该回退到 nunitlite 或 nunit3-console。

对于那些只是从特定版本运行 nunit 测试的人来说,我认为还有更多的自由度。

我们应该使 CI 规范化,可能使用 NUnitLite 进行所有框架测试,然后使用控制台、VSTest 适配器和 UWP 运行器进行端到端测试。

假设 CI 是可靠的,如果测试资源管理器、ReSharper、NCrunch 和我们的 CI 脚本之间存在细微差别,对我来说似乎没问题。 说这些 IDE 内工具应该被忽略是我认为是贡献和错误的障碍,因为这甚至不是我的工作流程。 我理想的工作流程:

  1. 定位现有测试或编写新测试
  2. 固定该测试装置,以便在打字时快速重新运行测试(更好的是,开始连续测试)
  3. 实施变更
  4. 在创建 Git 提交之前,运行.\build.ps1 -t test以确保通过和失败符合预期
  5. 如果有任何意外,请查找并固定我不知道的受影响测试,然后转到第 3 步

在测试对跑步者敏感的罕见情况下,我不确定让它们对跑步者不敏感是否具有挑战性。 它不会比我为 ILMerge 编写的集成测试更糟糕,我对 ReSharper 和 NCrunch 卷影副本具有弹性。

@aolszowka我 100% 同意你的观点,无论我们做什么,我们都应该尊重贡献者的时间,让贡献文档易于使用和更新。

@jnm2我喜欢你的“规范”方法。 我怀疑在测试资源管理器中让一切顺利运行会很容易,但值得尝试。

对于任何在 nunit 上工作的人来说,知道何时切换到较低级别的测试仍然很有用,而且很重要。

我们可以做的最重要的事情是建立独立的系统和集成测试。

这可能是根本原因。 在编写测试以从 FrameworkController 获取 XML 时,我注意到TestContext.WorkDirectory已更改为C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE

https://github.com/nunit/nunit/blob/81fcc7c047c09fcb5a86989d0829716ca7d08e1e/src/NUnitFramework/framework/Api/DefaultTestAssemblyBuilder.cs#L137

调用栈:

>   nunit.framework.dll!NUnit.Framework.Api.DefaultTestAssemblyBuilder.Build(System.Reflection.Assembly assembly, string suiteName, System.Collections.Generic.IDictionary<string, object> options) Line 137    C#
    nunit.framework.dll!NUnit.Framework.Api.DefaultTestAssemblyBuilder.Build(string assemblyNameOrPath, System.Collections.Generic.IDictionary<string, object> options) Line 114    C#
    nunit.framework.dll!NUnit.Framework.Api.NUnitTestAssemblyRunner.Load(string assemblyNameOrPath, System.Collections.Generic.IDictionary<string, object> settings) Line 154   C#
    nunit.framework.dll!NUnit.Framework.Api.FrameworkController.LoadTests() Line 204    C#

这是因为TestContext.WorkDirectory是静态可变状态:

https://github.com/nunit/nunit/blob/81fcc7c047c09fcb5a86989d0829716ca7d08e1e/src/NUnitFramework/framework/TestContext.cs#L96 -L101

这意味着它由所有测试(!)共享,包括并发测试。 任何依赖于 WorkDirectory 的测试都必须标记为[NonParallelizable]才能正确。

我很久以前就注意到了这个问题。 某处有问题。

NonParallelizable 是不够的。 如果任何测试修改了 WorkDirectory(正如许多 NUnit 测试所做的那样),那么依赖它的其他测试很可能会失败。

这完全取决于测试执行的顺序,这在 NUnit 中是未定义的。

意图是工作目录应该设置一次并且在运行时保持不变。 任何其他美国错误。

是否有理由不允许每个执行上下文都有一个独立的工作目录?

@CharliePoole我们将如何实现这一目标? 我们处于一个特殊的位置,因为框架测试测试 FrameworkController,一个控制器在一个控制器运行中运行。

撇开我们的测试不谈, WorkDirectory的含义是“用户设置的目录,用于接收运行的所有输出文件”。 所以测试不应该能够改变它。

对于我们自己的测试,我们需要能够设置它,但是如果我们做得对,该设置应该不会影响其他测试。 我们可能做得不对。 😜

在紧要关头,我们可以使它不可更改并停止测试。 <ducks>

这实际上是一个很酷的想法 - 跟踪是否已设置静态字段并在此之后跳过设置? 这样它是不可更改的,我没有看到任何检查DefaultTestAssemblyBuilder设置它的测试,所以我们应该很好!

有一些 NUnit 测试会改变它,如果它不可改变,它们可能会失败。

@oznetmaster我搜索过但找不到任何改变它的 NUnit 测试,除非意外。 你有什么好用的吗?

我将不得不搜索我的档案。

我已经通过执行已讨论的操作解决了我的 CF 构建中的问题。 只允许设置一次该值。 我检查它是否为空,如果是,则允许设置它。

                if (options.ContainsKey (FrameworkPackageSettings.WorkDirectory))
                    TestContext.DefaultWorkDirectory = options[FrameworkPackageSettings.WorkDirectory] as string;
                else
                    if (TestContext.DefaultWorkDirectory == null)
                        TestContext.DefaultWorkDirectory = Directory.GetCurrentDirectory ();

有问题的测试是那些调用 DefaultTestAssemblyBuilder.Build 的测试,其选项不包括 FrameworkPackageSettings.WorkDirectory,导致 TestContext.DefaultWorkDirectory 被 CurrentDirectory 覆盖。 这意味着如果 WorkDirectory 已在顶级执行中设置,它将被测试覆盖,并且永远不会恢复。

听起来我们最好采用相同的方法?

为我工作。 我的 CF 构建通过了 100% 的 NUnit 测试。

@OmicronPersei如果你在接下来的几天里,你能给@oznetmaster修复一下吗?

是的! 今晚试试

由于 nunit3-vs-adapter#528 导致其他问题,我无法真正重现此错误。 想法?

@OmicronPersei哦。 我不知道。 使用正确设置WorkDirectory的 .runsettings 会是一个很好的解决方法吗?

好的,我试过了。 TestCaseSourceCanAccessWorkDirectory成功,但StackTracesAreFiltered失败,OP 中的消息/堆栈跟踪相同。

我认为 StackTracesAreFiltered 应该提高到 5。这是一个气味测试,以便我们注意到是否添加了新框架,以便我们确保它没有失控。

TestCaseSourceCanAccessWorkDirectory怎么样,或者它仍然在这个 PR 的范围内?

对于TestCaseCanAccessWorkDirectory, @oznetmaster的修复是否解决了它? 如果没有,我们将不得不进一步调查。

我无法在我的机器上重现这个问题,有问题的测试对我来说通过了。

不用担心,其他人可以做那部分。 我也喜欢较小的 PR。

只是想打扫房间; 有什么理由让这个问题仍然存在,或者我们可以用某种类型的解决方案来关闭它吗? (即使它是 WONTFIX)。

不,谢谢你指出。 关闭。

此页面是否有帮助?
0 / 5 - 0 等级