走进 .Net 单元测试

走进 .Net 单元测试

Intro

“不会写单元测试的程序员不是合格的程序员,不写单元测试的程序员不是优秀程序员。”

—— 一只想要成为一个优秀程序员的渣逼程序猿。

那么问题来了,什么是单元测试,如何做单元测试。

单元测试定义

按照*上的说法,单元测试(Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。 程序单元是应用的最小可测试部件。在面向对象编程中,最小单元就是方法,包括基类、抽象类、或者派生类(子类)中的方法。 按照通俗的理解,一个单元测试判断某个特定场条件下某个特定方法的行为,如斐波那契数列算法,冒泡排序算法。

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。 对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义, 如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。 总的来说,单元就是人为规定的最小的被测功能模块。 单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

—— 百度百科 http://baike.baidu.com/view/106237.htm

进行单元测试的好处

  1. 它是一种验证行为

    程序中的每一项功能都是测试来验证它的正确性。

  2. 它是一种设计行为

    编写单元测试将使我们从调用者观察、思考。 特别是先写测试(test-first),迫使我们把程序设计成易于调用和可测试的,有利于程序的解耦和模块化。

  3. 它是一种编写文档的行为

    单元测试是一种无价的文档,它是展示函数或类如何使用的最佳文档。这份文档是可编译、可运行的,并且它保持最新,永远与代码同步。

  4. 它具有回归性

    自动化的单元测试避免了代码出现回归,编写完成之后,可以随时随地的快速运行测试。

  5. 高效

    自动化的单元测试节省了开发上调试BUG的时间,绝大多数BUG可以通过单元测试测试出来,并且可以减少测试人员的测试时间。有时候通过写单元测试能够更好的完善自己程序的逻辑,让程序变得更加美好。

    —— 单元测试的优点 http://jingyan.baidu.com/article/d713063522ab4e13fdf47533.html

单元测试的原则:

  • 可重复运行的
  • 持续长期有效,并且返回一致的结果
  • 在内存中运行,没有外部依赖组件(比如说真实的数据库,真实的文件存储等)
  • 快速返回结果
  • 一个测试方法只测试一个问题

VS单元测试 【MsTest】使用

VS单元测试的主要类:Assert、StringAssert、CollectionAssert,具体可参照 MSDN介绍

有些时候我们需要对测试的方法用到的数据或配置进行初始化,有几个特殊的测试方法。

如果需要针对测试中的所有虚拟用户迭代仅执行一次初始化操作,请使用 TestInitializeAttribute。

初始化方法的运行顺序如下:

  1. 用 AssemblyInitializeAttribute 标记的方法。
  2. 用 ClassInitializeAttribute 特性标记的方法。
  3. 用 TestInitializeAttribute 特性标记的方法。
  4. 用 TestMethodAttribute 特性标记的方法。

单元测试 使用示例

 using Microsoft.VisualStudio.TestTools.UnitTesting;

 namespace ConsoleApplication1Test
{
[TestClass]
public class MainTest
{
#region TestFail [TestMethod]
public void TestFail0()
{
Assert.Fail();
} [TestMethod]
public void TestFail1()
{
Assert.Fail("Test is fail");
} [TestMethod]
public void TestFail2()
{
Assert.Fail("Test3 is fail,{0}", "hahaha");
}
#endregion #region TestInconclusive 忽略
[TestMethod]
public void TestInconclusive0()
{
Assert.Inconclusive();
} [TestMethod]
public void TestInconclusive1()
{
Assert.Inconclusive("Inconclusive");
} [TestMethod]
public void TestInconclusive2()
{
Assert.Inconclusive("Inconclusive,{0}", "hehehe");
}
#endregion #region LogicTest #region Null
[TestMethod]
public void IsNullTest()
{
Assert.IsNull(null);
} [TestMethod]
public void IsNotNullTest()
{
Assert.IsNotNull();
}
#endregion #region True || False
[TestMethod]
public void IsTrueTest()
{
Assert.IsTrue( == );
} [TestMethod]
public void IsFalseTest()
{
Assert.IsFalse( > );
}
#endregion #region AreSame
[TestMethod]
public void AreSameTest()
{
//不要向 AreSame() 传递值类型的值,因为他们转换为 Object 后永久不会相等,值类型的值比较请使用 AreEqual()
Assert.AreSame(, );
} [TestMethod]
public void AreSameTest1()
{
object obj = new object(), obj1 = obj;
Assert.AreSame(obj, obj1, "same");
} [TestMethod]
public void StringAreSameTest0()
{
string str1 = "hello", str2 = "hello";
Assert.AreSame(str1, str2);
} [TestMethod]
public void StringAreSameTest1()
{
string str1 = "hello", str2 = "Hello";
Assert.AreSame(str1, str2);
} [TestMethod]
public void AreNotSameTest()
{
object obj = new object(), obj1 = new object();
Assert.AreNotSame(obj, obj1);
}
#endregion #region AreEqual
[TestMethod]
public void AreEqualTest()
{
Assert.AreEqual(, );
} [TestMethod]
public void AreNotEqualTest()
{
Assert.AreNotEqual(, );
} [TestMethod]
public void AreEqualTest1()
{
object obj = new object(), obj1 = obj;
Assert.AreEqual(obj, obj1);
} [TestMethod]
public void AreNotEqualTest1()
{
object obj = new object(), obj1 = new object();
Assert.AreNotEqual(obj, obj1);
} [TestMethod]
public void AreEqualTest2()
{
object obj = new object(), obj1 = new object();
Assert.AreEqual(obj, obj1);
// Assert.Equals()不用于断言,请使用 Assert.AreEquals() 或 Assert.AreNotEquals()
//Assert.Equals(obj, obj1);
} [TestMethod]
public void StringAreEqualTest0()
{
string str = "hello", str1 = "hello";
Assert.AreEqual(str, str1);
} [TestMethod]
public void StringAreEqualTest1()
{
string str = "hello", str1 = "Hello";
Assert.AreEqual(str, str1, true);
}
#endregion #region IsInstanceOfType [TestMethod]
public void IsInstanceOfTypeTest()
{
B b = new B();
Assert.IsInstanceOfType(b, typeof(A));
} [TestMethod]
public void IsNotInstanceOfTypeTest()
{
A a = new A();
Assert.IsNotInstanceOfType(a, typeof(B));
}
#endregion #endregion #region 测试初始化和清理
[AssemblyInitialize()]
public static void AssemblyInit(TestContext context)
{
System.Console.WriteLine("AssemblyInit " + context.TestName);
} [ClassInitialize()]
public static void ClassInit(TestContext context)
{
System.Console.WriteLine("ClassInit " + context.TestName);
} [TestInitialize]
public void Initialize()
{
System.Console.WriteLine("TestMethodInit");
} [TestCleanup]
public void Cleanup()
{
System.Console.WriteLine("TestMethodCleanup");
} [ClassCleanup]
public static void ClassCleanup()
{
System.Console.WriteLine("ClassCleanup");
} [AssemblyCleanup]
public static void AssemblyCleanup()
{
System.Console.WriteLine("AssemblyCleanup");
}
#endregion
} public class A { } public class B : A { } }

Ms Test单元测试

MsTest 和 Nunit区别

MS Test框架是Visual Studio自带的测试框架,可以通过新建一个Unit Test Project工程, 也可以建一个Class Libary,然后添加对Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll的引用。 然后就是创建测试用例,进行测试即可。

NUnit Test框架是一个xUnit家族种的第4个主打产品,完全由C#语言来编写,支持所有的.Net语言。 使用NUnit框架,我们需要下载安装包,安装后使用独立客户端进行使用。使用方法与MS Test类似

有一些是NUnit中的,但是MS Test框架中是没有的: - Assert.IsNaN - Assert.IsEmpty - Assert.IsNotEmpty - Assert.Greater - Assert.GreaterOrEqual - Assert.Less - Assert.LessOrEqual - Assert.IsAssignableFrom - Assert.IsNotAssignableFrom - Assert.Igore - CollectionAssert.IsEmpty - CollectionAssert.IsNotEmpty - StringAssert.AreEqualIgnoringCase - StringAssert.IsMatch - FileAssert.AreEqual - FileAssert.AreNotEqual

同时支持两种测试框架

可以通过宏判断来同时支持这两个框架,在测试前添加以下代码:

 #if !NUNIT
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Category = Microsoft.VisualStudio.TestTools.UnitTesting.DescriptionAttribute;
#else
using NUnit.Framework;
using TestClass = NUnit.Framework.TestFixtureAttribute;
using TestMethod = NUnit.Framework.TestAttribute;
using TestInitialize = NUnit.Framework.SetUpAttribute;
using TestCleanup = NUnit.Framework.TearDownAttribute;
using TestContext = System.Object;
using ClassCleanup = NUnit.Framework.TestFixtureTearDownAttribute;
using ClassInitialize = NUnit.Framework.TestFixtureSetUpAttribute;
#endif

Nunit测试使用示例

 #region NUNIT

     /// <summary>
/// This test fixture attempts to exercise all the syntactic
/// variations of Assert without getting into failures, errors
/// or corner cases.Thus, some of the tests may be duplicated
/// in other fixtures.
///
/// Each test performs the same operations using the classic
/// syntax(if available) and the new syntax in both the
/// helper-based and inherited forms.
///
/// This Fixture will eventually be duplicated in other
/// supported languages.
/// </summary>
[TestFixture]
public class AssertSyntaxTests : AssertionHelper
{
#region Simple Constraint Tests
[Test]
public void IsNull()
{
object nada = null; // Classic syntax
Assert.IsNull(nada); // Constraint Syntax
Assert.That(nada, Is.Null); // Inherited syntax
Expect(nada, Null);
} [Test]
public void IsNotNull()
{
// Classic syntax
Assert.IsNotNull(); // Constraint Syntax
Assert.That(, Is.Not.Null); // Inherited syntax
Expect(, Not.Null);
} [Test]
public void IsTrue()
{
// Classic syntax
Assert.IsTrue( + == ); // Constraint Syntax
Assert.That( + == , Is.True);
Assert.That( + == ); // Inherited syntax
Expect( + == , True);
Expect( + == );
} [Test]
public void IsFalse()
{
// Classic syntax
Assert.IsFalse( + == ); // Constraint Syntax
Assert.That( + == , Is.False); // Inherited syntax
Expect( + == , False);
} [Test]
public void IsNaN()
{
double d = double.NaN;
float f = float.NaN; // Classic syntax
Assert.IsNaN(d);
Assert.IsNaN(f); // Constraint Syntax
Assert.That(d, Is.NaN);
Assert.That(f, Is.NaN); // Inherited syntax
Expect(d, NaN);
Expect(f, NaN);
} [Test]
public void EmptyStringTests()
{
// Classic syntax
Assert.IsEmpty("");
Assert.IsNotEmpty("Hello!"); // Constraint Syntax
Assert.That("", Is.Empty);
Assert.That("Hello!", Is.Not.Empty); // Inherited syntax
Expect("", Empty);
Expect("Hello!", Not.Empty);
} [Test]
public void EmptyCollectionTests()
{
// Classic syntax
Assert.IsEmpty(new bool[]);
Assert.IsNotEmpty(new int[] { , , }); // Constraint Syntax
Assert.That(new bool[], Is.Empty);
Assert.That(new int[] { , , }, Is.Not.Empty); // Inherited syntax
Expect(new bool[], Empty);
Expect(new int[] { , , }, Not.Empty);
}
#endregion #region TypeConstraint Tests
[Test]
public void ExactTypeTests()
{
// Classic syntax workarounds
Assert.AreEqual(typeof(string), "Hello".GetType());
Assert.AreEqual("System.String", "Hello".GetType().FullName);
Assert.AreNotEqual(typeof(int), "Hello".GetType());
Assert.AreNotEqual("System.Int32", "Hello".GetType().FullName); // Constraint Syntax
Assert.That("Hello", Is.TypeOf(typeof(string)));
Assert.That("Hello", Is.Not.TypeOf(typeof(int))); // Inherited syntax
Expect("Hello", TypeOf(typeof(string)));
Expect("Hello", Not.TypeOf(typeof(int)));
} [Test]
public void InstanceOfTests()
{
// Classic syntax
Assert.IsInstanceOf(typeof(string), "Hello");
Assert.IsNotInstanceOf(typeof(string), ); // Constraint Syntax
Assert.That("Hello", Is.InstanceOf(typeof(string)));
Assert.That(, Is.Not.InstanceOf(typeof(string))); // Inherited syntax
Expect("Hello", InstanceOf(typeof(string)));
Expect(, Not.InstanceOf(typeof(string)));
} [Test]
public void AssignableFromTypeTests()
{
// Classic syntax
Assert.IsAssignableFrom(typeof(string), "Hello");
Assert.IsNotAssignableFrom(typeof(string), ); // Constraint Syntax
Assert.That("Hello", Is.AssignableFrom(typeof(string)));
Assert.That(, Is.Not.AssignableFrom(typeof(string))); // Inherited syntax
Expect("Hello", AssignableFrom(typeof(string)));
Expect(, Not.AssignableFrom(typeof(string)));
}
#endregion #region StringConstraint Tests
[Test]
public void SubstringTests()
{
string phrase = "Hello World!";
string[] array = new string[] { "abc", "bad", "dba" }; // Classic Syntax
StringAssert.Contains("World", phrase); // Constraint Syntax
Assert.That(phrase, Does.Contain("World"));
// Only available using new syntax
Assert.That(phrase, Does.Not.Contain("goodbye"));
Assert.That(phrase, Does.Contain("WORLD").IgnoreCase);
Assert.That(phrase, Does.Not.Contain("BYE").IgnoreCase);
Assert.That(array, Is.All.Contains("b")); // Inherited syntax
Expect(phrase, Contains("World"));
// Only available using new syntax
Expect(phrase, Not.Contains("goodbye"));
Expect(phrase, Contains("WORLD").IgnoreCase);
Expect(phrase, Not.Contains("BYE").IgnoreCase);
Expect(array, All.Contains("b"));
} [Test]
public void StartsWithTests()
{
string phrase = "Hello World!";
string[] greetings = new string[] { "Hello!", "Hi!", "Hola!" }; // Classic syntax
StringAssert.StartsWith("Hello", phrase); // Constraint Syntax
Assert.That(phrase, Does.StartWith("Hello"));
// Only available using new syntax
Assert.That(phrase, Does.Not.StartWith("Hi!"));
Assert.That(phrase, Does.StartWith("HeLLo").IgnoreCase);
Assert.That(phrase, Does.Not.StartWith("HI").IgnoreCase);
Assert.That(greetings, Is.All.StartsWith("h").IgnoreCase); // Inherited syntax
Expect(phrase, StartsWith("Hello"));
// Only available using new syntax
Expect(phrase, Not.StartsWith("Hi!"));
Expect(phrase, StartsWith("HeLLo").IgnoreCase);
Expect(phrase, Not.StartsWith("HI").IgnoreCase);
Expect(greetings, All.StartsWith("h").IgnoreCase);
} [Test]
public void EndsWithTests()
{
string phrase = "Hello World!";
string[] greetings = new string[] { "Hello!", "Hi!", "Hola!" }; // Classic Syntax
StringAssert.EndsWith("!", phrase); // Constraint Syntax
Assert.That(phrase, Does.EndWith("!"));
// Only available using new syntax
Assert.That(phrase, Does.Not.EndWith("?"));
Assert.That(phrase, Does.EndWith("WORLD!").IgnoreCase);
Assert.That(greetings, Is.All.EndsWith("!")); // Inherited syntax
Expect(phrase, EndsWith("!"));
// Only available using new syntax
Expect(phrase, Not.EndsWith("?"));
Expect(phrase, EndsWith("WORLD!").IgnoreCase);
Expect(greetings, All.EndsWith("!"));
} [Test]
public void EqualIgnoringCaseTests()
{
string phrase = "Hello World!"; // Classic syntax
StringAssert.AreEqualIgnoringCase("hello world!", phrase); // Constraint Syntax
Assert.That(phrase, Is.EqualTo("hello world!").IgnoreCase);
//Only available using new syntax
Assert.That(phrase, Is.Not.EqualTo("goodbye world!").IgnoreCase);
Assert.That(new string[] { "Hello", "World" },
Is.EqualTo(new object[] { "HELLO", "WORLD" }).IgnoreCase);
Assert.That(new string[] { "HELLO", "Hello", "hello" },
Is.All.EqualTo("hello").IgnoreCase); // Inherited syntax
Expect(phrase, EqualTo("hello world!").IgnoreCase);
//Only available using new syntax
Expect(phrase, Not.EqualTo("goodbye world!").IgnoreCase);
Expect(new string[] { "Hello", "World" },
EqualTo(new object[] { "HELLO", "WORLD" }).IgnoreCase);
Expect(new string[] { "HELLO", "Hello", "hello" },
All.EqualTo("hello").IgnoreCase);
} [Test]
public void RegularExpressionTests()
{
string phrase = "Now is the time for all good men to come to the aid of their country.";
string[] quotes = new string[] { "Never say never", "It's never too late", "Nevermore!" }; // Classic syntax
StringAssert.IsMatch("all good men", phrase);
StringAssert.IsMatch("Now.*come", phrase); // Constraint Syntax
Assert.That(phrase, Does.Match("all good men"));
Assert.That(phrase, Does.Match("Now.*come"));
// Only available using new syntax
Assert.That(phrase, Does.Not.Match("all.*men.*good"));
Assert.That(phrase, Does.Match("ALL").IgnoreCase);
Assert.That(quotes, Is.All.Matches("never").IgnoreCase); // Inherited syntax
Expect(phrase, Matches("all good men"));
Expect(phrase, Matches("Now.*come"));
// Only available using new syntax
Expect(phrase, Not.Matches("all.*men.*good"));
Expect(phrase, Matches("ALL").IgnoreCase);
Expect(quotes, All.Matches("never").IgnoreCase);
}
#endregion #region Equality Tests
[Test]
public void EqualityTests()
{
int[] i3 = new int[] { , , };
double[] d3 = new double[] { 1.0, 2.0, 3.0 };
int[] iunequal = new int[] { , , }; // Classic Syntax
Assert.AreEqual(, + );
Assert.AreEqual(i3, d3);
Assert.AreNotEqual(, + );
Assert.AreNotEqual(i3, iunequal); // Constraint Syntax
Assert.That( + , Is.EqualTo());
Assert.That( + == );
Assert.That(i3, Is.EqualTo(d3));
Assert.That( + , Is.Not.EqualTo());
Assert.That(i3, Is.Not.EqualTo(iunequal)); // Inherited syntax
Expect( + , EqualTo());
Expect( + == );
Expect(i3, EqualTo(d3));
Expect( + , Not.EqualTo());
Expect(i3, Not.EqualTo(iunequal));
} [Test]
public void EqualityTestsWithTolerance()
{
// CLassic syntax
Assert.AreEqual(5.0d, 4.99d, 0.05d);
Assert.AreEqual(5.0f, 4.99f, 0.05f); // Constraint Syntax
Assert.That(4.99d, Is.EqualTo(5.0d).Within(0.05d));
Assert.That(4.0d, Is.Not.EqualTo(5.0d).Within(0.5d));
Assert.That(4.99f, Is.EqualTo(5.0f).Within(0.05f));
Assert.That(4.99m, Is.EqualTo(5.0m).Within(0.05m));
Assert.That(3999999999u, Is.EqualTo(4000000000u).Within(5u));
Assert.That(, Is.EqualTo().Within());
Assert.That(4999999999L, Is.EqualTo(5000000000L).Within(5L));
Assert.That(5999999999ul, Is.EqualTo(6000000000ul).Within(5ul)); // Inherited syntax
Expect(4.99d, EqualTo(5.0d).Within(0.05d));
Expect(4.0d, Not.EqualTo(5.0d).Within(0.5d));
Expect(4.99f, EqualTo(5.0f).Within(0.05f));
Expect(4.99m, EqualTo(5.0m).Within(0.05m));
Expect(499u, EqualTo(500u).Within(5u));
Expect(, EqualTo().Within());
Expect(4999999999L, EqualTo(5000000000L).Within(5L));
Expect(5999999999ul, EqualTo(6000000000ul).Within(5ul));
} [Test]
public void EqualityTestsWithTolerance_MixedFloatAndDouble()
{
// Bug Fix 1743844
Assert.That(2.20492d, Is.EqualTo(2.2d).Within(0.01f),
"Double actual, Double expected, Single tolerance");
Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01d),
"Double actual, Single expected, Double tolerance");
Assert.That(2.20492d, Is.EqualTo(2.2f).Within(0.01f),
"Double actual, Single expected, Single tolerance");
Assert.That(2.20492f, Is.EqualTo(2.2f).Within(0.01d),
"Single actual, Single expected, Double tolerance");
Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01d),
"Single actual, Double expected, Double tolerance");
Assert.That(2.20492f, Is.EqualTo(2.2d).Within(0.01f),
"Single actual, Double expected, Single tolerance");
} [Test]
public void EqualityTestsWithTolerance_MixingTypesGenerally()
{
// Extending tolerance to all numeric types
Assert.That(202d, Is.EqualTo(200d).Within(),
"Double actual, Double expected, int tolerance");
Assert.That(4.87m, Is.EqualTo().Within(.),
"Decimal actual, int expected, Double tolerance");
Assert.That(4.87m, Is.EqualTo(5ul).Within(),
"Decimal actual, ulong expected, int tolerance");
Assert.That(, Is.EqualTo().Within(),
"int actual, int expected, int tolerance");
Assert.That(487u, Is.EqualTo().Within(),
"uint actual, int expected, int tolerance");
Assert.That(487L, Is.EqualTo().Within(),
"long actual, int expected, int tolerance");
Assert.That(487ul, Is.EqualTo().Within(),
"ulong actual, int expected, int tolerance");
}
#endregion #region Comparison Tests
[Test]
public void ComparisonTests()
{
// Classic Syntax
Assert.Greater(, );
Assert.GreaterOrEqual(, );
Assert.GreaterOrEqual(, ); // Constraint Syntax
Assert.That(, Is.GreaterThan());
Assert.That(, Is.GreaterThanOrEqualTo());
Assert.That(, Is.AtLeast());
Assert.That(, Is.GreaterThanOrEqualTo());
Assert.That(, Is.AtLeast()); // Inherited syntax
Expect(, GreaterThan());
Expect(, GreaterThanOrEqualTo());
Expect(, AtLeast());
Expect(, GreaterThanOrEqualTo());
Expect(, AtLeast()); // Classic syntax
Assert.Less(, );
Assert.LessOrEqual(, );
Assert.LessOrEqual(, ); // Constraint Syntax
Assert.That(, Is.LessThan());
Assert.That(, Is.LessThanOrEqualTo());
Assert.That(, Is.AtMost());
Assert.That(, Is.LessThanOrEqualTo());
Assert.That(, Is.AtMost()); // Inherited syntax
Expect(, LessThan());
Expect(, LessThanOrEqualTo());
Expect(, AtMost());
Expect(, LessThanOrEqualTo());
Expect(, AtMost());
}
#endregion #region Collection Tests
[Test]
public void AllItemsTests()
{
object[] ints = new object[] { , , , };
object[] doubles = new object[] { 0.99, 2.1, 3.0, 4.05 };
object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; // Classic syntax
CollectionAssert.AllItemsAreNotNull(ints);
CollectionAssert.AllItemsAreInstancesOfType(ints, typeof(int));
CollectionAssert.AllItemsAreInstancesOfType(strings, typeof(string));
CollectionAssert.AllItemsAreUnique(ints); // Constraint Syntax
Assert.That(ints, Is.All.Not.Null);
Assert.That(ints, Has.None.Null);
Assert.That(ints, Is.All.InstanceOf(typeof(int)));
Assert.That(ints, Has.All.InstanceOf(typeof(int)));
Assert.That(strings, Is.All.InstanceOf(typeof(string)));
Assert.That(strings, Has.All.InstanceOf(typeof(string)));
Assert.That(ints, Is.Unique);
// Only available using new syntax
Assert.That(strings, Is.Not.Unique);
Assert.That(ints, Is.All.GreaterThan());
Assert.That(ints, Has.All.GreaterThan());
Assert.That(ints, Has.None.LessThanOrEqualTo());
Assert.That(strings, Is.All.Contains("a"));
Assert.That(strings, Has.All.Contains("a"));
Assert.That(strings, Has.Some.StartsWith("ba"));
Assert.That(strings, Has.Some.Property("Length").EqualTo());
Assert.That(strings, Has.Some.StartsWith("BA").IgnoreCase);
Assert.That(doubles, Has.Some.EqualTo(1.0).Within(.)); // Inherited syntax
Expect(ints, All.Not.Null);
Expect(ints, None.Null);
Expect(ints, All.InstanceOf(typeof(int)));
Expect(strings, All.InstanceOf(typeof(string)));
Expect(ints, Unique);
// Only available using new syntax
Expect(strings, Not.Unique);
Expect(ints, All.GreaterThan());
Expect(ints, None.LessThanOrEqualTo());
Expect(strings, All.Contains("a"));
Expect(strings, Some.StartsWith("ba"));
Expect(strings, Some.StartsWith("BA").IgnoreCase);
Expect(doubles, Some.EqualTo(1.0).Within(.));
} [Test]
public void SomeItemTests()
{
object[] mixed = new object[] { , , "", null, "four", };
object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; // Not available using the classic syntax // Constraint Syntax
Assert.That(mixed, Has.Some.Null);
Assert.That(mixed, Has.Some.InstanceOf(typeof(int)));
Assert.That(mixed, Has.Some.InstanceOf(typeof(string)));
Assert.That(strings, Has.Some.StartsWith("ba"));
Assert.That(strings, Has.Some.Not.StartsWith("ba")); // Inherited syntax
Expect(mixed, Some.Null);
Expect(mixed, Some.InstanceOf(typeof(int)));
Expect(mixed, Some.InstanceOf(typeof(string)));
Expect(strings, Some.StartsWith("ba"));
Expect(strings, Some.Not.StartsWith("ba"));
} [Test]
public void NoItemTests()
{
object[] ints = new object[] { , , , , };
object[] strings = new object[] { "abc", "bad", "cab", "bad", "dad" }; // Not available using the classic syntax // Constraint Syntax
Assert.That(ints, Has.None.Null);
Assert.That(ints, Has.None.InstanceOf(typeof(string)));
Assert.That(ints, Has.None.GreaterThan());
Assert.That(strings, Has.None.StartsWith("qu")); // Inherited syntax
Expect(ints, None.Null);
Expect(ints, None.InstanceOf(typeof(string)));
Expect(ints, None.GreaterThan());
Expect(strings, None.StartsWith("qu"));
} [Test]
public void CollectionContainsTests()
{
int[] iarray = new int[] { , , };
string[] sarray = new string[] { "a", "b", "c" }; // Classic syntax
Assert.Contains(, iarray);
Assert.Contains("b", sarray);
CollectionAssert.Contains(iarray, );
CollectionAssert.Contains(sarray, "b");
CollectionAssert.DoesNotContain(sarray, "x");
// Showing that Contains uses NUnit equality
CollectionAssert.Contains(iarray, 1.0d); // Constraint Syntax
Assert.That(iarray, Has.Member());
Assert.That(sarray, Has.Member("b"));
Assert.That(sarray, Has.No.Member("x"));
// Showing that Contains uses NUnit equality
Assert.That(iarray, Has.Member(1.0d)); // Only available using the new syntax
// Note that EqualTo and SameAs do NOT give
// identical results to Contains because
// Contains uses Object.Equals()
Assert.That(iarray, Has.Some.EqualTo());
Assert.That(iarray, Has.Member());
Assert.That(sarray, Has.Some.EqualTo("b"));
Assert.That(sarray, Has.None.EqualTo("x"));
Assert.That(iarray, Has.None.SameAs(1.0d));
Assert.That(iarray, Has.All.LessThan());
Assert.That(sarray, Has.All.Length.EqualTo());
Assert.That(sarray, Has.None.Property("Length").GreaterThan()); // Inherited syntax
Expect(iarray, Contains());
Expect(sarray, Contains("b"));
Expect(sarray, Not.Contains("x")); // Only available using new syntax
// Note that EqualTo and SameAs do NOT give
// identical results to Contains because
// Contains uses Object.Equals()
Expect(iarray, Some.EqualTo());
Expect(sarray, Some.EqualTo("b"));
Expect(sarray, None.EqualTo("x"));
Expect(iarray, All.LessThan());
Expect(sarray, All.Length.EqualTo());
Expect(sarray, None.Property("Length").GreaterThan());
} [Test]
public void CollectionEquivalenceTests()
{
int[] ints1to5 = new int[] { , , , , };
int[] twothrees = new int[] { , , , , , };
int[] twofours = new int[] { , , , , , }; // Classic syntax
CollectionAssert.AreEquivalent(new int[] { , , , , }, ints1to5);
CollectionAssert.AreNotEquivalent(new int[] { , , , , }, ints1to5);
CollectionAssert.AreNotEquivalent(new int[] { , , , }, ints1to5);
CollectionAssert.AreNotEquivalent(new int[] { , , , , , , }, ints1to5);
CollectionAssert.AreNotEquivalent(twothrees, twofours); // Constraint Syntax
Assert.That(new int[] { , , , , }, Is.EquivalentTo(ints1to5));
Assert.That(new int[] { , , , , }, Is.Not.EquivalentTo(ints1to5));
Assert.That(new int[] { , , , }, Is.Not.EquivalentTo(ints1to5));
Assert.That(new int[] { , , , , , , }, Is.Not.EquivalentTo(ints1to5)); // Inherited syntax
Expect(new int[] { , , , , }, EquivalentTo(ints1to5));
Expect(new int[] { , , , , }, Not.EquivalentTo(ints1to5));
Expect(new int[] { , , , }, Not.EquivalentTo(ints1to5));
Expect(new int[] { , , , , , , }, Not.EquivalentTo(ints1to5));
} [Test]
public void SubsetTests()
{
int[] ints1to5 = new int[] { , , , , }; // Classic syntax
CollectionAssert.IsSubsetOf(new int[] { , , }, ints1to5);
CollectionAssert.IsSubsetOf(new int[] { , , , , }, ints1to5);
CollectionAssert.IsNotSubsetOf(new int[] { , , }, ints1to5);
CollectionAssert.IsNotSubsetOf(new int[] { , , , , }, ints1to5); // Constraint Syntax
Assert.That(new int[] { , , }, Is.SubsetOf(ints1to5));
Assert.That(new int[] { , , , , }, Is.SubsetOf(ints1to5));
Assert.That(new int[] { , , }, Is.Not.SubsetOf(ints1to5)); // Inherited syntax
Expect(new int[] { , , }, SubsetOf(ints1to5));
Expect(new int[] { , , , , }, SubsetOf(ints1to5));
Expect(new int[] { , , }, Not.SubsetOf(ints1to5));
}
#endregion #region Property Tests
[Test]
public void PropertyTests()
{
string[] array = { "abc", "bca", "xyz", "qrs" };
string[] array2 = { "a", "ab", "abc" };
ArrayList list = new ArrayList(array); // Not available using the classic syntax // Constraint Syntax
Assert.That(list, Has.Property("Count"));
Assert.That(list, Has.No.Property("Length")); Assert.That("Hello", Has.Length.EqualTo());
Assert.That("Hello", Has.Length.LessThan());
Assert.That("Hello", Has.Property("Length").EqualTo());
Assert.That("Hello", Has.Property("Length").GreaterThan()); Assert.That(array, Has.Property("Length").EqualTo());
Assert.That(array, Has.Length.EqualTo());
Assert.That(array, Has.Property("Length").LessThan()); Assert.That(array, Has.All.Property("Length").EqualTo());
Assert.That(array, Has.All.Length.EqualTo());
Assert.That(array, Is.All.Length.EqualTo());
Assert.That(array, Has.All.Property("Length").EqualTo());
Assert.That(array, Is.All.Property("Length").EqualTo()); Assert.That(array2, Has.Some.Property("Length").EqualTo());
Assert.That(array2, Has.Some.Length.EqualTo());
Assert.That(array2, Has.Some.Property("Length").GreaterThan()); Assert.That(array2, Is.Not.Property("Length").EqualTo());
Assert.That(array2, Is.Not.Length.EqualTo());
Assert.That(array2, Has.No.Property("Length").GreaterThan()); Assert.That(List.Map(array2).Property("Length"), Is.EqualTo(new int[] { , , }));
Assert.That(List.Map(array2).Property("Length"), Is.EquivalentTo(new int[] { , , }));
Assert.That(List.Map(array2).Property("Length"), Is.SubsetOf(new int[] { , , , , }));
Assert.That(List.Map(array2).Property("Length"), Is.Unique); Assert.That(list, Has.Count.EqualTo()); // Inherited syntax
Expect(list, Property("Count"));
Expect(list, Not.Property("Nada")); Expect("Hello", Length.EqualTo());
Expect("Hello", Property("Length").EqualTo());
Expect("Hello", Property("Length").GreaterThan()); Expect(array, Property("Length").EqualTo());
Expect(array, Length.EqualTo());
Expect(array, Property("Length").LessThan()); Expect(array, All.Length.EqualTo());
Expect(array, All.Property("Length").EqualTo()); Expect(array2, Some.Property("Length").EqualTo());
Expect(array2, Some.Length.EqualTo());
Expect(array2, Some.Property("Length").GreaterThan()); Expect(array2, None.Property("Length").EqualTo());
Expect(array2, None.Length.EqualTo());
Expect(array2, None.Property("Length").GreaterThan()); Expect(Map(array2).Property("Length"), EqualTo(new int[] { , , }));
Expect(Map(array2).Property("Length"), EquivalentTo(new int[] { , , }));
Expect(Map(array2).Property("Length"), SubsetOf(new int[] { , , , , }));
Expect(Map(array2).Property("Length"), Unique); Expect(list, Count.EqualTo()); }
#endregion #region Not Tests
[Test]
public void NotTests()
{
// Not available using the classic syntax // Constraint Syntax
Assert.That(, Is.Not.Null);
Assert.That(, Is.Not.True);
Assert.That(, Is.Not.False);
Assert.That(2.5, Is.Not.NaN);
Assert.That( + , Is.Not.EqualTo());
Assert.That( + , Is.Not.Not.EqualTo());
Assert.That( + , Is.Not.Not.Not.EqualTo()); // Inherited syntax
Expect(, Not.Null);
Expect(, Not.True);
Expect(, Not.False);
Expect(2.5, Not.NaN);
Expect( + , Not.EqualTo());
Expect( + , Not.Not.EqualTo());
Expect( + , Not.Not.Not.EqualTo());
}
#endregion #region Operator Tests
[Test]
public void NotOperator()
{
// The ! operator is only available in the new syntax
Assert.That(, !Is.Null);
// Inherited syntax
Expect(, !Null);
} [Test]
public void AndOperator()
{
// The & operator is only available in the new syntax
Assert.That(, Is.GreaterThan() & Is.LessThan());
// Inherited syntax
Expect(, GreaterThan() & LessThan());
} [Test]
public void OrOperator()
{
// The | operator is only available in the new syntax
Assert.That(, Is.LessThan() | Is.GreaterThan());
Expect(, LessThan() | GreaterThan());
} [Test]
public void ComplexTests()
{
Assert.That(, Is.Not.Null & Is.Not.LessThan() & Is.Not.GreaterThan());
Expect(, Not.Null & Not.LessThan() & Not.GreaterThan()); Assert.That(, !Is.Null & !Is.LessThan() & !Is.GreaterThan());
Expect(, !Null & !LessThan() & !GreaterThan()); // No longer works at all under 3.0
// TODO: Evaluate why we wanted to use null in this setting in the first place
#if false
// TODO: Remove #if when mono compiler can handle null
#if MONO
Constraint x = null;
Assert.That(, !x & !Is.LessThan() & !Is.GreaterThan());
Expect(, !x & !LessThan() & !GreaterThan());
#else
Assert.That(, !(Constraint)null & !Is.LessThan() & !Is.GreaterThan());
Expect(, !(Constraint)null & !LessThan() & !GreaterThan());
#endif
#endif
}
#endregion #region Invalid Code Tests
// This method contains assertions that should not compile
// You can check by uncommenting it.
//public void WillNotCompile()
//{
// Assert.That(42, Is.Not);
// Assert.That(42, Is.All);
// Assert.That(42, Is.Null.Not);
// Assert.That(42, Is.Not.Null.GreaterThan(10));
// Assert.That(42, Is.GreaterThan(10).LessThan(99)); // object[] c = new object[0];
// Assert.That(c, Is.Null.All);
// Assert.That(c, Is.Not.All);
// Assert.That(c, Is.All.Not);
//}
#endregion
} #endregion

Nunit 单元测试

单元测试参考资料

上一篇:剑指Offer:重建二叉树【7】


下一篇:《剑指offer》重建二叉树