NUnit vs. xUnit

本文关键字:xUnit vs NUnit | 更新日期: 2023-09-27 18:28:10

NUnit和xUnit.net之间有什么区别?开发其中两个而不仅仅是一个有什么意义?

我读到xUnit是由NUnit的发明者开发的:

xUnit.net是一个用于.net Framework的单元测试工具编写人NUnit的最初发明者

另一方面:

NUnit是一个适用于所有.Net语言的单元测试框架。。这个目前的生产版本2.6是第七个主要版本xUnit-based单元测试工具

那么真相在哪里呢?

NUnit vs. xUnit

在编写此答案时,最新的NUnit版本是v3.5,xUnit.net是v2.1。

这两个框架都很棒,并且都支持并行测试运行(不过方式不同)NUnit自2002年以来一直存在,它被广泛使用,有很好的文档记录,并拥有一个庞大的社区,而xUnit.net更现代,更依赖TDD,更可扩展,也在.net核心开发中流行。它也有很好的记录。

除此之外,我注意到的主要区别是xUnit.net运行测试方法的方式。因此,在NUnit中,我们有一个测试类和一组测试方法

NUnit创建测试类的一个新实例,然后从同一实例运行所有测试方法。

xUnit.net为每个测试方法创建一个新的测试类实例。

因此,不能使用字段或属性在测试方法之间共享数据,这是一种糟糕的做法,因为我们的测试方法会相互依赖,这在TDD中是不可接受的。因此,如果你使用xunit.net,你可以确保你的测试方法是完全孤立的。

如果你愿意在测试方法之间共享一些数据,xUnit会允许你这样做。因此,默认情况下,所有测试方法都是完全隔离的,但你可以在特定情况下故意打破这种隔离。我喜欢这种态度,这就是为什么我更喜欢它。

您混淆了单个工具(xUnit.net)的名称和一整类单元测试框架(xUnit,x指的是一种语言/环境,例如JUnit、NUnit…)的名称。

xUnit遵循了一个新的概念,避免了旧的"SetUp"answers"TearDown"方法。它迫使我们使用IDisposable和构造函数,就像我们作为.NET开发人员应该做的那样。xUnit也有一个清晰的上下文共享概念。

xUnit Cons:

获取测试上下文的可用性尚未实现。

xUnit的一个好处是它可以在不同的类中找到测试,并并行运行它们。如果您有许多测试用例,这可以节省大量时间。

当然,您可以关闭它,或者控制它的操作(线程数量、每个类的线程数、每个程序集的测试数等)。

使用两个测试项目来查看这个示例解决方案,一个使用xUnit,另一个使用NUnit。

您可以在xUnit中阅读更多关于并行测试的信息。

10年前有人问过这个问题,但情况确实发生了变化。

下面是一个很好的视频,将xUnit、NUnit和MSTest与代码示例进行比较一旦你看到,努尼特到处都有,而其他人没有或拥有更少。

我不会对xUnit(以及MSTest)说一些宽容的话——一个糟糕的文档化绿色沙盒,对TDD的理解不完整,文档化不好,缺乏酷的功能。此外,TDD是一个概念,而不是一个受IDE或框架限制的框架或smth。如果"你"需要边界来遵循TDD并且不编写糟糕的代码,那么你需要阅读书籍,而不是设计新的框架或使用xUnit。

什么是xUnit?

  • 几乎没有文件
  • 没有setupt和teardown,而是手动编写包装器
  • 没有一次性设置(假设您编写集成或e2e测试,并且需要设置默认的DB数据)
  • 无写线
  • 没有测试上下文
  • 没有其他有助于更好地控制和装饰测试的酷属性
  • 糟糕的断言
  • 较差的并行度设置

MSTest是唯一一个并发的。企业中有人用MSTest替换框架吗?我认为没有。

NUnit是一个易于使用和学习的现代全功能框架,20多年来一直位居榜首。它有完整的文档,良好的架构(xUnit没有Setup和onetimesetup?真的用构造函数代替它吗?这就像把一个bug命名为功能而不是修复),良好的社区,没有童年问题。

截至2023年,我相信您选择两个测试框架中的哪一个并不重要,它们都以不同的方式提供了一些相似的功能。

不同的受众可能会根据他们的需求选择一个特定的框架,但对于大多数通用目的,以下是我在测试框架中要寻找的几个关键内容

  1. 编写清晰易读的断言

  2. 测试类的生命周期更简单,在行为方面并没有隐藏的惊喜。

  3. 我的测试框架是一段帮助我测试和维护代码库的代码,我希望它易于使用,有良好的社区支持和良好的文档记录。

现在比较xunit.net&nunit基于我的喜好

  1. 断言-xunit.net和;nunit有Assert类,允许我们为不同的情况编写断言,如检查相等、异常、不确定、可跳过的测试用例等。两者都是相同的。人们还将FluentAssertions库与这些测试框架一起广泛使用,以获得易于阅读的断言。

  2. 控制台运行程序-xunit.net和;nunit有命令行测试运行程序。但令我惊讶的是,xunit.net不允许直接从命令行传递参数。它建议我们在理想情况下应该传递来自外部源(如环境变量/配置文件)的参数。这种固执己见的论点对我来说没有多大意义

    另一方面,Nunit已经建立了对将论点传递到测试用例的支持。

  3. 测试生命周期-如果你想在测试实例级别设置一些连接变量/通用设置变量,两者都以不同的方式支持它。我想说,xunit.net一开始就有一种非常固执己见的心态,不支持设置和拆卸方法。他们的论点是,这会使代码难以读取和调试。我真的不相信这个论点。他们建议我们使用构造函数进行设置,使用IDisposable接口进行拆卸操作。另一方面,Nunit有SetUp和TearDown方法,可用于在实例级别设置和处理变量。请确保每个测试用例都会创建您在SetUp方法中声明的类/变量的新实例,除非您声明静态变量。

    两者都支持setup&在固定装置级别拆卸。同样,xunit.net由于需要扩展接口而使这一问题复杂化。Nunit有OneTimeSetup和OneTimeTearDown方法。

  4. 社区支持-我亲自研究了这两个框架的文档,更喜欢nunit的文档。xunit.net几乎没有文档,欢迎在这里提出异议。两者都有良好的社区支持stackoverflow和帮助是可用的。

  5. 并行性——我个人在选择测试框架时不会考虑测试用例的性能/并行性,但xunit.net确实在fixture级别、测试实例级别和汇编级别提供了很好的并行性支持。nunit还提供了对测试实例和类fixture级别的并行性的支持。

总之,两者都提供了相似的功能。xunit.net强加的观点和理由对我来说并没有多大意义。我宁愿选择nunit,因为if提供的使用简单。

有一个特性使我能够从XUnit(2.x)切换到NUnit(3.x),那就是:

XUnit不能与Console.WriteLine()一起工作,而NUnit可以

当我发现没有简单的方法让Console.WriteLine在XUnit中工作时,我无法描述我有多沮丧,尤其是当我试图让一小段代码工作时。

我认为这是一个标准的基准用户案例,您应该始终使标准输出与您的测试框架一起工作。我知道这不是一个好的做法,我知道还有其他选择,比如输出处理程序之类的。试用Console.WriteLine的用户尤其是新用户,无法将任何内容打印到屏幕上是非常非常令人失望和沮丧的。

1。xUnit具有紧凑的API。NUnit为流畅断言提供了更多的方法、属性和语法

Equal(2, a);                   // xUnit
Assert.That(a, Is.EqualTo(2)); // NUnit

2.xUnit为每个测试方法调用测试类的构造函数。相反,NUnit为所有测试调用构造函数一次

因此,使用NUnit,您必须在方法中设置测试,标记为[setup]属性。

在xUnit中,以下测试将通过,因为测试是相互隔离的:


int _a = 3;
[Fact]
public void Test1() => Equal(3, _a++);
[Fact]
public void Test2() => Equal(3, _a++);

在NUnit中,以下测试将失败

int _a = 3;
[Test]
public void Test1() => Assert.That(_a++, Is.EqualTo(3));
[Test]
public void Test2() => Assert.That(_a++, Is.EqualTo(3)); // NUnit fails here 

3.xUnit有更多类型安全的相等断言

NUnit将成功编译以下代码,但测试将失败:

[Test]
public void Test1()
{
    var ct = new CancellationTokenSource();
    Assert.That(ct, Is.EqualTo(ct.Token));     
    Assert.AreEqual(ct, Is.EqualTo(ct.Token)); 
    // AreEqual works with Object type. This is type-unsafe
    // public static void AreEqual(object? expected, object? actual) {...}
}

在xUnit的情况下,不可能出现这些错误。xUnit相等断言默认情况下是通用的:


[Fact]
public void Test1()
{
    var ct = new CancellationTokenSource();
    Equal(ct, ct.Token); 
    // Compile time error, Equal method is generic
    // public static void Equal<T>(T expected, T actual) {...}
}

我将添加我的经验,这是其他人错过的-在NUnit中,您必须初始化[SetUp]方法中的每个字段,这有两个含义

  • 有时您更希望在声明的同时进行初始化,以提高可读性
  • 有时,您可能会发现自己处于一种棘手的难以调试的情况,在这种情况下,由于在声明级别编写了一个小的初始化(未被注意到),测试是不确定的

尽管在额外的方法中设置显式属性来说明它的用途看起来很好,但这不是自然的,我们不以这种方式编写常规代码,因此我更喜欢常规对象初始化。

例如,我喜欢这样的初始化:

public class Tests
{
  private readonly DateTime _fakeCurrentTime = F.Create<DateTime>();

对我来说,它清晰易读。我更喜欢它而不是:

public class Tests
{
  private DateTime _fakeCurrentTime; # can't use readonly here which feels unnatural
  [SetUp]
  public void SetUp()
  {
    _fakeCurrentTime = F.Create<DateTime>();
  }

这样的NUnit设置不是可选的(对于那些为了可读性而喜欢这样做的人来说),它是强制性的,只跳过一个字段可能会导致棘手的非确定性测试(尽管我了解NUnit的工作原理,多年来一直使用它,但这种情况发生在我身上的次数很少)。

因此,在我看来,我们在生产代码中使用的常规类初始化更简单、更自然、更清晰。

NUnit和xUnit都是.NET的流行单元测试框架。这两个框架为创建和运行单元测试提供了类似的功能,但两者之间存在一些关键区别。

其中一个主要区别是用于编写测试用例的语法。NUnit基于旧的Java JUnit框架,并遵循类似的组织测试的结构,包括用于定义测试固定装置、设置和拆卸方法的属性。

例如,在NUnit中,您可以编写这样的测试用例:

public class MyTests {
    [Test]    
    public void TestMethod() {
        // test code here
    }
}

在xUnit中,您可以编写这样的测试用例:

public class MyTests {
    [Fact]
    public void TestMethod() {
        // test code here
    }
}

另一个区别是xUnit内置了对数据驱动测试的支持,允许您使用不同的输入数据运行相同的测试用例。NUnit还支持数据驱动的测试,但它要求您使用单独的库或属性。

xUnit还提供了对异步测试的支持,允许您使用async和await关键字编写异步测试用例。NUnit也支持异步测试,但它需要使用单独的库或属性。

这两个框架都得到了积极的维护和支持,所以这在很大程度上取决于个人偏好。一些开发人员更喜欢xUnit更简洁、更具表现力的语法,而另一些开发人员则更喜欢NUnit更传统的基于属性的语法。