【问题标题】:Is there anything I can do in NUnit that I can't do in MSTest?有什么我可以在 NUnit 中做而我在 MSTest 中做不到的事情吗?
【发布时间】:2009-09-28 15:42:21
【问题描述】:

这个问题已经在许多不同的论坛中以各种形式提出过,但是,恕我直言,我一直没能找到真正清楚回答的地方,所以我打算重新整理一下,再问一次.

我基本上在 Microsoft 商店工作。我们使用 TFS,我们所有的开发人员都订阅了 MSDN,包括 VS 的 Team Suite 版本。所以我们可以访问 MSTest。

我已经阅读了各种 NUnit 与 MSTest 的比较,开发人员社区似乎绝大多数都选择了 NUnit。但给出的理由似乎从来都不是压倒性的或令人信服的,至少在我们的情况下是这样。 (NUnit 更新更频繁,NUnit 更快,NUnit 不需要 TFS 等)

如果我愿意,我可以使用 NUnit,但必须捍卫使用没有正式支持的开源软件。我需要一个相当有说服力的理由。

为了证明使用 NUnit 而不是 MSTest 的合理性,我基本上必须回答的是:有什么我可以在 NUnit 中做而我在 MSTest 中无法做到的事情吗?

【问题讨论】:

    标签: nunit mstest


    【解决方案1】:
    • NUnit 包含允许实施参数化测试的 [TestCase] 属性。这在 MSTest 中不存在开箱即用 - 但可以通过可扩展性来完成。
    • MsTest 的 ExpectedException 属性存在一个错误,即预期的消息永远不会被真正断言,即使它是错误的 - 测试将通过。
    • NUnit 附带一个 Assert.Throws API,允许在特定代码行而不是整个方法上测试异常。 MSTest 也有类似的功能(由为 NUnit 执行此功能的同一个人实现),但 MSTest 没有提供。
    • NUnit 包含开箱即用的流畅版本的 Assert API。 MSTest 具有执行此操作的第三方扩展,但没有随 MSTest 提供。
    • NUnit 允许抽象类成为测试夹具(因此您可以继承测试夹具)。 MsTest 允许这样做,但将抽象类限制为单个程序集。
    • NUnit 允许将非公共类作为测试装置(最新版本)
    • NUnit 的创建完全是为了单元测试的想法。 MSTest 是为测试而创建的 - 还有一些单元测试。
    • NUnit 包含 PNunit(使用 NUnit 运行并行测试)。 MSTest 在 Visual Studio 2010 中添加了此功能,可通过 XML 进行配置

    【讨论】:

    • Nunit 快得多 --> 但它带来了 TestClass 而不是 TestMethod 隔离的代价,这使得 MSTest 当然更慢...
    • TestClass 隔离并不是导致 MSTest 变慢的原因。 xUnit.net 有测试类隔离,比 NUnit 快。
    • MSTest 有 DataDriven 测试,基本上是参数化测试
    • 另外,NUnit 不需要构建/测试服务器来安装 Visual Studio
    • @RoyOsherove 请仔细阅读 ExpectedExceptionAttribute 文档,没有地方说明测试异常消息,因此它不是未断言的错误。第二个参数是未抛出预期异常类型时显示的断言消息,而不是预期的异常消息。 IE。就像 Assert.IsTrue(condition, message) 中的第二个参数一样。
    【解决方案2】:

    Roy,您的大量信息已经过时,尤其是与 2010 年有关的信息;

    Nunit 包含一个 [TestCase] 属性,允许实现参数化测试。这在 MSTest 中不存在

    这可以在 2010 年使用单元测试可扩展性来实现。

    MSTest 的 ExpectedException 属性有一个错误,即预期的消息永远不会被真正断言,即使它是错误的 - 测试将通过。

    正确的还是有的

    NUnit 有一个 Assert.Throws API,允许在特定代码行而不是整个方法上测试异常(不过您可以轻松地自己实现这个)

    Jim 为 MSTest 实现了一个 Assert.Throws 版本,同时他为 NUnit 实现了原始实现,NUnit 已包含在后续版本中,MSTest 没有,但它仍然可以使用。

    NUnit 包含一个流畅版本的 Assert API(如前所述 - Assert.That..)

    其中有几个是由第 3 方为 MSTest 实施的

    NUnit 更快

    查看 Jamie 的评论,他设法让 MSTest 运行得更快 :-)

    NUnit 可以在 32 位和 64 位中运行测试(MSTest 只能在 32 位 IIRC 中运行)

    不是在 2010 年,而是内置了 64 位支持。

    NUnit 允许抽象类成为测试夹具(因此您可以继承测试夹具)。 MsTest 没有。

    这可行,但不能跨程序集,这确实限制了它的用处。

    NUnit 允许非公共类作为测试装置(最新版本)

    还在那里

    NUnit 的创建完全是为了单元测试的想法。 MSTest 是为测试而创建的 - 还有一些单元测试。

    正确,有很多误解认为 MSTest 与 Nunit 相同,但 MSTest 是一个通用框架。

    NUnit 包含 PNunit(使用 NUnit 运行并行测试)。 MSTest 仅在 vs 2010 中添加了此功能

    正确的是,有一个 XML 配置设置允许控制并行度。

    【讨论】:

    • @Euan Garden - 你提到 Jim 在 NUnit 中创建了 Assert.Throws。他实际上是为 xUnit.Net 做的。我认为 Jim 自从加入 Microsoft 后就没有向 NUnit 添加任何代码。
    • 在 xUnit 实现之后,他为 MSTEST 和 Nunit 实现了 ExpectedException 的替代方案。 NUnit 包含在 2.5 中,但 Jims 补丁适用于 2.4:jamesnewkirk.typepad.com/posts/2008/06/replacing-expec.html
    • 作为一个仅供参考,处理这种情况的正确方法是编辑他的答案,而不是添加另一个答案。
    • MsTest 中缺少 Assert.Throws()(在长期使用 NUnit 后不得不使用 MsTest)让我非常困扰,以至于我为它编写了一个可扩展的包装器,其中还包括 Assert.Throws。来源可以在这里找到:github.com/bbraithwaite/MSTestExtensions
    • @EuanGarden 请仔细阅读 ExpectedExceptionAttribute 文档,没有地方说明测试异常消息,所以它不是一个没有断言的错误。第二个参数是未抛出预期异常类型时显示的断言消息,而不是预期的异常消息。 IE。就像 Assert.IsTrue(condition, message) 中的第二个参数一样。
    【解决方案3】:

    NUnit 有一个richer assert API。 api特别优雅(流畅,甚至),例如

    Assert.That(Is.Unique, myResults);  // assert: myResults is a collection of unique items
    

    如果您看过 JUnit 的 Hamcrest 扩展,您就会认出这种风格。

    它还有一个不断增长的set of extensions,比如性能测试和一个excellent VS plugin

    【讨论】:

      【解决方案4】:

      我可以为您指出一些关于 MSTest 挫折的博客:

      公平地说,这些人正试图在非 TFS 构建服务器上设置 MSTest。他们的一些问题不适用于您的情况。

      我们主要是一家 Microsoft 商店,并使用 TFS 进行源代码控制。但是,我们使用TeamCity 进行持续集成;我们喜欢它,它与 TFS 的集成相当好。我从未使用过 MSTest;我们已经使用 NUnit 多年了,没有理由改变。

      MSTest 应该与 Team Suite 紧密集成,这对它有利(因为您的公司已经为此支付了巨额费用)。

      NUnit 具有较少的供应商锁定,并具有丰富的 API。正如 serg10 所指出的,Assert.That 语法特别强大和优雅。

      最后,您可以编写好的单元测试而无需所有花哨的功能。其中一些甚至可能会妨碍(这是xUnit.net 背后的理论)。我建议您的团队在一个测试框架上进行标准化;避免在 MSTest 中使用一些代码,在 NUnit 中使用其他代码。

      我认为编写好的测试比选择框架更重要。考虑阅读The Art of Unit Testing: with Examples in .NET,编写一些测试,然后看看 MSTest 是否足以满足您团队的需求。

      编辑:单元测试艺术的附录 B 有一些关于微软单元测试框架的好方法。它提到YUnit 作为扩展MSTest 是多么麻烦的一个例子。但是,由于紧密集成,作者确实建议为 Team System 用户使用 MSTest。

      【讨论】:

        【解决方案5】:

        我在 MsTest 和 NUnit 之间有一个很好的方法。 您可以使用 MSTest 框架来运行您的测试(每个测试的 TestClass 属性和 TestMethod 属性),但使用 NUnit Assert API。

        只要这样做:

        using Microsoft.VisualStudio.TestTools.UnitTesting; 
        using Assert = NUnit.Framework.Assert;  
        

        现在您可以使用 Assert.That(..) 并且仍然拥有 TFS 自动构建和测试报告。 你的测试可以在VS、TestDriven.net或Resharper中运行,没关系,测试会失败或正确通过,失败输出会根据NUnit框架。

        请看这里: http://alsagile.com/archive/2010/03/09/stop-the-war-between-nunit-and-mstest-make-them.aspx

        【讨论】:

        • 谢谢。由于我无法控制的原因,我需要搬到 MSTest。上述解决方案解决了许多过渡问题。
        【解决方案6】:
        1. MSTest 测试运行程序是非确定性的,这足以让您不敢使用它。我无法始终使用集成测试运行器从 TFS 2010 运行 MSTest;它在项目构建和构建代理之间出现一些不同的错误消息(并且不一致)。
        2. MSTest 有时(并非始终如一地)中断,因为它会泄漏内存——即使使用最新版本的 Visual Studio,我们仍然会发生内存不足异常。这个问题的解决方法很糟糕。
        3. 我对 MSTest 有其他一些小问题,并在博客上写了很多使用 MSTest 的解决方法:http://www.pseale.com/blog/TFSAsYourBuildCIServerOnlyPositiveTakeaways1Of2.aspx

        我在将我们从 MSTest 切换到 NUnit 时发现了这个问题,因为由于 MSTest,我们不再信任 CI 构建的结果。切换到 NUnit 将使我们(最终)相信 CI 构建失败是真实的,而不是另一个 MSTest 故障。这是真正的答案——只有使用 NUnit(或其他一些非 MSTest 测试运行程序)我们才能信任我们的 CI 构建

        【讨论】:

          【解决方案7】:

          请仔细阅读 ExpectedExceptionAttribute 文档,它没有说明测试异常消息,所以它不是一个没有断言的错误。

          第二个参数是未抛出预期异常类型时显示的断言消息,而不是预期的异常消息。 IE。就像 Assert.IsTrue(condition, message) 中的第二个参数一样。

          【讨论】:

            【解决方案8】:

            我一直致力于为 TestDriven.Net 3.0 中的 MSTest 提供一流的支持。在以前的版本中,MSTest 支持非常基础(似乎很少有人使用 MSTest)。

            从 TestDriven.Net 3.0 Beta 2 开始,对 MSTest 的所有单元测试相关属性都有相当全面的支持。甚至还支持使用 DataSource 属性的数据驱动测试。您的测试也将以接近 NUnit 的速度执行!

            如果您使用 MSTest,我很想知道您在使用 TestDriven.Net 3.0 Beta 2(或更高版本)执行时是否有任何单元测试失败。

            请在您的 MSTest 项目上尝试一下,并告诉我您的进展情况: http://www.testdriven.net/download.aspx

            注意,它不支持 DeploymentItem 或 HostType 属性。您可以使用“复制到输出目录”项目项设置而不是 DeploymentItem。

            【讨论】:

              【解决方案9】:

              您可以更改 NUnit 中的代码,因为它是开源的。使用 MSTest 无法做到这一点。

              【讨论】:

                【解决方案10】:

                http://fluentassertions.codeplex.com。你可以做类似的事情

                "ABCDEFGHI".Should().StartWith("AB").And.EndWith("HI").And.Contain("EF").And.HaveLength(9);
                
                new[] { 1, 2, 3 }.Should().HaveCount(4, "because we thought we put three items in the 
                collection"))
                
                dtoCollection.Should().Contain(dto => dto.Id != null);
                
                collection.Should().HaveCount(c => c >= 3);
                
                dto.ShouldHave().AllPropertiesBut(d => d.Id).EqualTo(customer);
                
                dt1.Should().BeWithin(TimeSpan.FromHours(50)).Before(dt2); 
                
                Action action = () => recipe.AddIngredient("Milk", 100, Unit.Spoon);
                action
                   .ShouldThrow<RuleViolationException>()
                   .WithMessage("Cannot change the unit of an existing ingredient")
                   .And.Violations.Should().Contain(BusinessRule.CannotChangeIngredientQuanity
                

                【讨论】:

                  【解决方案11】:

                  @戴夫汉娜 MS Test 开箱即用,因此无需担心部署和保持更新的组件。 它还通过设计与 Visual Studio 和其他 Microsoft 产品集成。

                  流畅的语法很好,但它不是功能差异,所以我会忽略它。更不用说您可以通过使用扩展库在 MS Test 中拥有相同的功能。

                  性能。 99% 的测试性能由被测系统控制,因此即使两个库之间 100% 的性能差异也会导致可忽略的整体性能差异。

                  开源与非开源:您从使用开源库中受益的机会微乎其微。例外情况是经常将更改拉入主干或有足够的资源来保持修改后的分支更新。

                  【讨论】:

                    【解决方案12】:

                    您可以使用 Mono 在 Linux 上轻松运行 NUnit 测试,但我认为您无法使用 MSTest 测试来做到这一点。

                    【讨论】:

                      猜你喜欢
                      • 2011-02-02
                      • 2011-03-17
                      • 2013-02-20
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-12-17
                      • 1970-01-01
                      • 2021-03-02
                      • 1970-01-01
                      相关资源
                      最近更新 更多