NUnit: Writing Test Code

Summary

* Based on NUnit version 2.4.8

Test code follows a standard formula:

  • Set up all conditions needed for testing (create any required objects, allocate any needed resources, etc.)
  • Call the method to be tested.
  • Verify that the tested functionality worked as expected.
  • Clean up any necessary test conditions.

Test Attributes

Each class that contains tests must be annotated with a [TestFixture] attribute. The class must be declared public (so that the test runners will run it; by default, classes are internal), and it must have a public, no-parameter, constructor.

Create individual methods annotated with [Test] attributes. Any public, parameterless method specified with a [Test] attribute will be run automatically by NUnit. You can include helper methods to support clean code in our tests as well, just don't mark them with a [Test] attribute.

NUnit lets you specify two methods to set up ([Setup] attribute) and then tear down ([TearDown] attribute) the environment for each one of the [Test] methods, executed, even if the test method throws an exception.

This can also be set up per TestFixture class, using the [TestFixtureSetup] and [TestFixtureTearDown] attributes. NUnit doesn't recreate the TestFixture class each time it runs a test and it discovers and runs the methods using reflection, so using the class Constructors would not work as expected.

[TestFixture] public void PerFixtureSetup() { ... } [TestFixtureTearDown] public void PerFixtureTeardown() { ... }

While setup and teardown methods generally come in pairs, they don't have to. Very often, a fixture will have a setup, but no teardown.

You can also define set-up methods across inheritance boundaries, in both base classes and derived classes. They will work together as if they were all defined in the same class.

Advanced Test Attributes

Use the [Ignore] attribute when you don't want the testing framework to run the specified tests.

[Test] [Ignore("Out of time. Will Complete on Monday. -- JJ" )] public void Something() { .. }

NUnit will report that this method was skipped and show a yellow bar in the GUI version.

Use the [Platform] attribute to ignore tests because of the platform on which you are running.

[Test] [Platform(Exclude = "Mono" )] public void RemoveOnEmpty() { .. } [Test, Platform(Exclude = "Net-1.0,Win95" )] public void EmptyStatusBar() { .. }

When using the [Platform] attribute, you will still get a green bar in the GUI even in the presence of tests ignored via this attribute. A comprehensive list of the platforms can be found in the NUnit documentation on http://nunit.org.

To test for a specific exception use the [ExpectedException] attribute.

[TestFixture] public class ImportListTests { [Test] [ExpectedException(typeof(ArgumentNullException))] public void NullList() { WhitePages.ImportList(null); // Shouldn't get to here } }

Once the expected exception fires, any remaining code in the test method will be skipped.

Test Categories

You can use NUnit categories to help sort out tests that run constantly versus long-running tests that should only run during the automated build. Categories are generally used for exclusion rather than inclusion.

A category is specified as an attribute. You provide a string to identify the category when you declare the method. Then when you run the tests, you can specify which categories you want to run (you can specify more than one).

[Test] [Category("Short" )] public void Use5Cities() { Assert.That(tsp.ShortestPath(5), Is.AtMost(140)); } // This one takes a while... [Test] [Category("Long" )] [Category("Jeffrey" )] public void Use50Cities() { Assert.That(tsp.ShortestPath(50), Is.AtMost(2300)); }

You can also mark entire fixtures as belonging to a category. And not all tests need categories.

You can specify the Explicit attribute: [Explicit("SpecialEquipmentNeeded" )] to run only when explicitly selected. This syntax automatically excludes the category from a run that doesn't specify any categories.

Each test should run independently of every other test; this allows you to run any individual test at any time, in any order.

NUnit Asserts

Asserts are the fundamental building block for unit tests and NUnit provides a number of different forms of assert as static methods in the Assert class.

Classic-style assertions

  • Assert.AreEqual
  • Assert.AreEqual(expected, actual [, string message])
  • Used to compare floating point numbers (floats or doubles in C#)
  • "tolerance" specifies just how close to "equals" you need the result to be
  • Assert.AreEqual(expected, actual, tolerance [string message])
  • Assert.Less
  • Assert.Less(argument1, argument2 [, string message] [, object[] parms])
  • Assert.Greater
  • Assert.Greater(argument1, argument2 [, string message] [, object[] parms])
  • Assert.GreaterOrEqual
  • Assert.GreaterOrEqual(argument1, argument2 [, string message] [, object[] parms])
  • Assert.LessOrEqual
  • Assert.LessOrEqual(argument1, argument2 [, string message] [, object[] parms])
  • Assert.IsNull
  • Asserts that the given object is null, failing otherwise
  • Assert.IsNull(object [, string message])
  • Assert.IsNotNull
  • Asserts that the given object is not null, failing otherwise
  • Assert.IsNotNull(object [, string message])
  • Assert.AreSame
  • Asserts that expected and actual refer to the same object, and fails the test if they do not
  • Assert.AreSame(expected, actual [, string message])
  • Assert.IsTrue
  • Asserts that the given boolean condition is true, otherwise the test fails
  • Assert.IsTrue(bool condition [, string message])
  • Assert.IsFalse
  • Asserts that the given boolean condition is false, otherwise the test fails
  • Assert.IsFalse(bool condition [, string message])
  • Assert.Fail
  • Fails the test immediately
  • Might be used to mark sections of code that should not be reached, but isn't really used much in practice
  • Assert.Fail([string message])

Constraint-style assertions

  • Constraint-based Assert Model (introduced in NUnit 2.4) utilizes only one Assert method named Assert.That().
  • Makes use of syntax helpers found in the NUnit.Framework.SyntaxHelpers namespace.
  • The most common overloads to the Assert.That() method are as follows:
  • Assert.That(object actual, IConstraint constraint)
  • Assert.That(object actual, IConstraint constraint, string message)
  • Assert.That(object actual, IConstraint constraint, string message, object[] parms)

Comparison Constraints

  • Is.Equal
  • Assert.That(actual, Is.EqualTo(expected))
  • Use constraint modifier, Within(), to specify a tolerance for floating point numbers
  • Assert.That(10.0/3.0, Is.EqualTo(3.33).Within(0.01f))
  • Use constraint modifier, IgnoreCase, to compare strings in a case-insensitive manner
  • Assert.That("Hello", Is.EqualTo("hello").IgnoreCase)
  • Is.Not.Equal
  • Assert.That(actual, Is.Not.EqualTo(expected))
  • Assert.That(actual, !Is.EqualTo(expected))
  • Is.AtMost
  • Assert.That(actual, Is.AtMost(expected))
  • Assert.That(actual, Is.LessThenOrEqualTo(expected))
  • Is.AtLeast
  • Assert.That(actual, Is.AtLeast(expected))
  • Assert.That(actual, Is.GreaterThenOrEqualTo(expected))
  • Has.Length
  • Asserts that actual has a Length property that returns the expected value
  • Note that it can be any object with a property named "Length", not just a string or Collection
  • Assert.That(actual, Has.Length(expected))

Condition Constraints

  • Is.Null
  • Asserts that expected is null, and fails the test if it is not
  • Assert.That(expected, Is.Null)
  • Assert.That(expected, !Is.Null)
  • Is.Not.Null
  • Assert.That(expected, Is.Not.Null)
  • Assert.That(expected, !Is.Not.Null)
  • Is.Empty
  • Asserts that expected is an empty collection or string, and fails the test if it is not
  • Assert.That(expected, Is.Empty)
  • Assert.That(expected, !Is.Empty)
  • Is.True
  • Asserts that expected is true, and fails the test if it is not
  • Assert.That(expected, Is.True)
  • Is.False
  • Asserts that expected is false, and fails the test if it is not
  • Assert.That(expected, Is.False)
  • Is.NaN
  • Asserts that expected is not a number, and fails the test if it is a number
  • Assert.That(expected, Is.NaN)
  • Is.Not.NaN
  • Asserts that expected is a number, and fails the test if it is not a number
  • Assert.That(expected, Is.Not.NaN)
  • Assert.That(expected, !Is.NaN)
  • Is.Unique
  • Assertion for Collections containing only unique items
  • Assert.That(collection, Is.Unique)

Type Constraints

  • Is.InstanceOfType
  • Asserts that actual is of type expected, or a derivation of that type
  • Assert.That(actual, Is.InstanceOfType(expected))
  • Is.Not.InstanceOfType
  • Asserts that actual is not of type expected, or not a derivation of that type
  • Assert.That(actual, Is.Not.InstanceOfType(expected))
  • Assert.That(actual, !Is.InstanceOfType(expected))

SameAs Constraints

  • Is.SameAs
  • To implement a "same referenced object" assertion
  • Assert.That(object, Is.SameAs(object))

String Constraints

  • Text.Contains
  • Tests that the expected value is contained within a Collection or String
  • Assert.That(phase, Text.Contains("tests fail"))
  • Assert.That(phase, Text.Contains("make").IgnoreCase)
  • Assert.That(collection, List.Contains(expected))
  • Text.StartsWith
  • Tests that the expected string is at the beginning of actual
  • This is case sensitive by default; to ignore case sensitivity, add the IgnoreCase constraint modifier
  • Assert.That(phase, Text.StartsWith("Make"))
  • Text.DoesNotStartWith
  • Assert.That(phase, Text.DoesNotStartWith("Break"))
  • Assert.That(phase, !Text.StartsWith("Break"))
  • Text.EndsWith
  • Assert.That(phase, Text.EndsWith("!"))
  • Assert.That(phase, Text.EndsWith("PASSING!").IgnoreCase)
  • Text.Matches
  • Tests that the expected regular expression string matches actual
  • Assert.That(phase, Text.Matches("Make.*tests.*pass"))
  • Text.DoesNotMatch
  • Assert.That(phase, Text.DoesNotMatch("your.*passing.*tests"))

Collection Constraints

  • A collection assertion where each item must pass the specified constraint
  • Assert.That(collection, Is.All.Not.Null)
  • Assert.That(collection, Is.All.InstanceOfType(typeof(string)))
  • Assert.That(collection, Is.All.GreaterThan(0))
  • A collection assertion where at least 1 item must pass the specified constraint
  • Assert.That(collection, Has.Some.Not.Null)
  • Assert.That(collection, Has.Some.InstanceOfType(typeof(string)))
  • Assert.That(collection, Has.Some.GreaterThan(2))
  • A collection assertion where each item must fail the specified constraint
  • Assert.That(collection, Has.None.Null)
  • Assert.That(collection, Has.None.InstanceOfType(typeof(double)))
  • Assert.That(collection, Has.None.GreaterThan(5))
  • A "unique items only" collection assertion
  • Assert.That(collection, Is.Unique)
  • A "must contain this item" collection assertion
  • Assert.That(collection, Has.Member(3))
  • Assert.That(collection, Has.Member("b"))
  • Assert.That(collection, Has.No.Member("x"))
  • An "equivalent" collection assertion
  • Two collections are equivalent if they contain the same items, in any order
  • Assert.That(new string[] {"c", "a", "b" }, Is.EquivalentTo(array))
  • Assert.That(new int[] { 1, 2, 2 }, Is.Not.EquivalentTo(array))
  • An "is a subset of" collection assertion
  • Tests that the elements of a Collection are contained within expected Collection, regardless of order
  • Assert.That(new int[] { 1, 3 }, Is.SubsetOf(array))

File Assert

  • FileAssert.AreEqual
  • FileAssert.AreNotEqual
  • Test whether two files are the same, byte for byte
  • FileAssert.AreEqual(FileInfo expected, FileInfo actual)
  • FileAssert.AreEqual(String pathToExpected, String pathToActual)