最完整的非信息单元测试框架备忘单


每个用户界面测试框架的一个重要部分是单元测试框架的使用。世界上最受欢迎的。网络世界是无信息的。但是,您找不到一个地方可以开始使用它的语法。所以,我决定创建一个完整的备忘单会很棒。我希望你会发现它有用。享受吧!

装置

Install-Package NUnit
Install-Package NUnit.TestAdapter
Install-Package Microsoft.NET.Test.Sdk

为了发现或执行测试用例,VSTest会根据您的项目配置调用测试适配器。(这就是为什么NUnit/xUnit/MSTest都要求您为您的单元测试项目安装一个测试适配器NuGet包)。所以不要。TestAdapter就是为此而存在的。

NUnit本身实现了测试框架和它的契约。因此,您需要添加一个NuGet引用来编写单元测试用例并编译它们。只有编译过的项目和测试适配器才能被Visual Studio使用。

测试执行工作流

using NUnit.Framework;
namespace NUnitUnitTests
{
    // A class that contains NUnit unit tests. (Required)
    [TestFixture]
    public class NonBellatrixTests
    {
        [OneTimeSetUp]
        public void ClassInit()
        {
            // Executes once for the test class. (Optional)
        }
        [SetUp]
        public void TestInit()
        {
            // Runs before each test. (Optional)
        }
        [Test]
        public void TestMethod()
        {
        }
        [TearDown]
        public void TestCleanup()
        {
            // Runs after each test. (Optional)
        }
        [OneTimeTearDown]
        public void ClassCleanup()
        {
            // Runs once after all tests in this class are executed. (Optional)
            // Not guaranteed that it executes instantly after all tests from the class.
        }
    }
}
// A SetUpFixture outside of any namespace provides SetUp and TearDown for the entire assembly.
[SetUpFixture]
public class MySetUpClass
{
    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
        // Executes once before the test run. (Optional)
    }
    [OneTimeTearDown]
    public void RunAfterAnyTests()
    {
        // Executes once after the test run. (Optional)
    }
}


从SetUpFixture进行一次性设置(每个程序集一次)
测试夹具的一次性设置(每个测试类一次)
SetUp(在每次课程测试之前)
测试1
拆卸(在该类的每次测试之后)
设置
测试2
拆卸
...
从测试夹具中获取一次(每个测试类一次)
从测试夹具进行一次性设置
...
从测试夹具中获取
从SetUpFixture获取一次权限(每个程序集一次)

属性比较

将NUnit与其他框架进行比较。

Image title

Image title

断言

断言——经典模型

经典的断言模型使用单独的方法来表达它能够表达的每个独立的断言。

Assert.AreEqual(28, _actualFuel); // Tests whether the specified values are equal. 
Assert.AreNotEqual(28, _actualFuel); // Tests whether the specified values are unequal. Same as AreEqual for numeric values.
Assert.AreSame(_expectedRocket, _actualRocket); // Tests whether the specified objects both refer to the same object
Assert.AreNotSame(_expectedRocket, _actualRocket); // Tests whether the specified objects refer to different objects
Assert.IsTrue(_isThereEnoughFuel); // Tests whether the specified condition is true
Assert.IsFalse(_isThereEnoughFuel); // Tests whether the specified condition is false
Assert.IsNull(_actualRocket); // Tests whether the specified object is null
Assert.IsNotNull(_actualRocket); // Tests whether the specified object is non-null
Assert.IsInstanceOf(_actualRocket, typeof(Falcon9Rocket)); // Tests whether the specified object is an instance of the expected type
Assert.IsNotInstanceOf(_actualRocket, typeof(Falcon9Rocket)); // Tests whether the specified object is not an instance of type
StringAssert.AreEqualIgnoringCase(_expectedBellatrixTitle, "Bellatrix"); // Tests whether the specified strings are equal ignoring their casing
StringAssert.Contains(_expectedBellatrixTitle, "Bellatrix"); // Tests whether the specified string contains the specified substring
StringAssert.DoesNotContain(_expectedBellatrixTitle, "Bellatrix"); // Tests whether the specified string doesn't contain the specified substring
StringAssert.StartsWith(_expectedBellatrixTitle, "Bellatrix"); // Tests whether the specified string begins with the specified substring
StringAssert.StartsWith(_expectedBellatrixTitle, "Bellatrix"); // Tests whether the specified string begins with the specified substring
StringAssert.IsMatch("(281)388-0388", @"(?d{3})?-? *d{3}-? *-?d{4}"); // Tests whether the specified string matches a regular expression
StringAssert.DoesNotMatch("281)388-0388", @"(?d{3})?-? *d{3}-? *-?d{4}"); // Tests whether the specified string does not match a regular expression
CollectionAssert.AreEqual(_expectedRockets, _actualRockets); // Tests whether the specified collections have the same elements in the same order and quantity.
CollectionAssert.AreNotEqual(_expectedRockets, _actualRockets); // Tests whether the specified collections does not have the same elements or the elements are in a different order and quantity.
CollectionAssert.AreEquivalent(_expectedRockets, _actualRockets); // Tests whether two collections contain the same elements.
CollectionAssert.AreNotEquivalent(_expectedRockets, _actualRockets); // Tests whether two collections contain different elements.
CollectionAssert.AllItemsAreInstancesOfType(_expectedRockets, _actualRockets); // Tests whether all elements in the specified collection are instances of the expected type
CollectionAssert.AllItemsAreNotNull(_expectedRockets); // Tests whether all items in the specified collection are non-null
CollectionAssert.AllItemsAreUnique(_expectedRockets); // Tests whether all items in the specified collection are unique
CollectionAssert.Contains(_actualRockets, falcon9); // Tests whether the specified collection contains the specified element
CollectionAssert.DoesNotContain(_actualRockets, falcon9); // Tests whether the specified collection does not contain the specified element
CollectionAssert.IsSubsetOf(_expectedRockets, _actualRockets); // Tests whether one collection is a subset of another collection
CollectionAssert.IsNotSubsetOf(_expectedRockets, _actualRockets); // Tests whether one collection is not a subset of another collection
Assert.Throws<ArgumentNullException>(() => new Regex(null)); // Tests whether the code specified by delegate throws exact given exception of type T


断言——约束模型

基于约束的断言模型对所有断言使用断言类的单一方法。执行每个断言所需的逻辑被嵌入到作为第二个参数传递给该方法的约束对象中。这个断言中的第二个参数使用NUnit的语法助手之一来创建一个等式约束。

Assert.That(28, Is.EqualTo(_actualFuel)); // Tests whether the specified values are equal. 
Assert.That(28, Is.Not.EqualTo(_actualFuel)); // Tests whether the specified values are unequal. Same as AreEqual for numeric values.
Assert.That(_expectedRocket, Is.SameAs(_actualRocket)); // Tests whether the specified objects both refer to the same object
Assert.That(_expectedRocket, Is.Not.SameAs(_actualRocket)); // Tests whether the specified objects refer to different objects
Assert.That(_isThereEnoughFuel, Is.True); // Tests whether the specified condition is true
Assert.That(_isThereEnoughFuel, Is.False); // Tests whether the specified condition is false
Assert.That(_actualRocket, Is.Null); // Tests whether the specified object is null
Assert.That(_actualRocket, Is.Not.Null); // Tests whether the specified object is non-null
Assert.That(_actualRocket, Is.InstanceOf<Falcon9Rocket>()); // Tests whether the specified object is an instance of the expected type
Assert.That(_actualRocket, Is.Not.InstanceOf<Falcon9Rocket>()); // Tests whether the specified object is not an instance of type
Assert.That(_actualFuel, Is.GreaterThan(20)); // Tests whether the specified object greater than the specified value


高级属性

作者属性

作者属性添加了关于测试作者的信息。它可以应用于测试夹具和测试。

[TestFixture]
[Author("Joro Doev", "joro.doev@bellatrix.solutions")]
public class RocketFuelTests
{
   [Test]
   public void RocketFuelMeassuredCorrectly_When_Landing() { /* ... */ }
   [Test]
   [Author("Ivan Penchev")]
   public void RocketFuelMeassuredCorrectly_When_Flying() { /* ... */ }
}


重复属性

在测试方法上使用RepeatAttribute来指定它应该被执行多次。如果任何重复失败,其余的不运行,并报告失败。

[Test]
[Repeat(10)]
public void RocketFuelMeassuredCorrectly_When_Flying() { /* ... */ }


组合属性

CombinatorialAttribute用于测试,以指定NUnit应为测试参数提供的单个数据项的所有可能组合生成测试用例。

[Test, Combinatorial]
public void CorrectFuelMeassured_When_X_Site([Values(1,2,3)] int x, [Values("A","B")] string s)
{
    ...
}

生成的测试:

当X_Site(1,“A”)时修正燃料消耗
当X_Site(1,“B”)时,修正燃料消耗
修正了当X点(2,“一”)
修正了当X站点(2,“乙”)
当X_Site(3,“A”)时修正燃料消耗
当X_Site(3,“B”)时,修正燃料消耗

成对属性

在测试中使用成对属性来指定NUnit应该以使用所有可能的值对的方式生成测试用例。

[Test, Pairwise]
public void ValidateLandingSiteOfRover_When_GoingToMars
    ([Values("a", "b", "c")] string a, [Values("+", "-")] string b, [Values("x", "y")] string c)
{
    Debug.WriteLine("{0} {1} {2}", a, b, c);
}

结果对:

a + y

a - x

b - y

b + x

c - x

c + y

随机属性

随机属性用于为参数化测试方法的单个数值参数指定一组随机值。

以下测试将执行15次,每个x值执行3次,每个x值与从-1.0到+1.0的5个随机双精度值相结合。

[Test]
public void GenerateRandomLandingSiteOnMoon([Values(1,2,3)] int x, [Random(-1.0, 1.0, 5)] double d)
{
    ...
}


范围属性

RangeAttribute用于指定为参数化测试方法的单个参数提供的值的范围。NUnit从所有可能的参数组合中创建测试用例——组合方法。

[Test]
public void CalculateJupiterBaseLandingPoint([Values(1,2,3)] int x, [Range(0.2,0.6)] double y)
{
    //...
}

生成的测试:

calculatejupiterbalaselandingpoint(1,0.2)
calculatejupiterbalaselandingpoint(1,0.4)
calculatejupiterbalaselandingpoint(1,0.6)
calculatejupiterbalaselandingpoint(2,0.2)
calculatejupiterbalaselandingpoint(2,0.4)
calculatejupiterbalaselandingpoint(2,0.6)
calculatejupiterbalaselandingpoint(3,0.2)
calculatejupiterbalaselandingpoint(3,0.4)
calculatejupiterbalaselandingpoint(3,0.6)

重试属性

RetryAttribute用于测试方法,以指定如果失败,应该重新运行该方法,最多可运行最大次数。

[Test]
[Retry(3)]
public void CalculateJupiterBaseLandingPoint([Values(1,2,3)] int x, [Range(0.2,0.6)] double y)
{
    //...
}


超时属性

timeout属性用于为测试用例指定超时值(以毫秒为单位)。如果测试用例运行的时间超过了指定的时间,它将被立即取消并报告为失败,同时显示一条消息,指示超时已过。

[Test, Timeout(2000)]
public void FireRocketToProximaCentauri()
{
    ...
}


并行执行测试

从NUnit 3.7开始,支持类内方法的并行执行。在早期的版本中,并行执行只适用于测试设备级的并行范围。儿童作为平行世界工作。放置在方法上的夹具和任何并行化属性都将被忽略。

[assembly: Parallelizable(ParallelScope.Fixtures)]
[assembly:LevelOfParallelism(3)]

并行化属性可以在多级测试中指定。较高级别的设置可能会影响较低级别的测试,除非这些较低级别的测试覆盖了继承的设置。

[TestFixture]
[Parallelizable(ParallelScope.Fixtures)]
public class TestFalcon9EngineLevels
{
    // ...
}