NUnit 2

Unity 5.5 ships with NUnit 2.6. It is accessible through the Window menu, Editor Test Runner. The documentation on NUnit 2 is good, but admittedly isn't very accessible. I will provide my collection of most important attributes and assertions, also with my comments (taken at the time of Unity 5.5 release), saving you the trouble of having to click through the whole documentation. My comments are shown in italic.

 

Attributes

[TestFixture]

This is the attribute that marks a class that contains tests and, optionally, setup or teardown methods.

  • It must be a publicly exported type or NUnit will not see it.
  • It must have a default constructor or NUnit will not be able to construct it.
  • The constructor should not have any side effects, since NUnit may construct the class multiple times in the course of a session.

[Test]

Method that contains the test. The Test attribute marks a specific method (inside a class that has already been marked as a TestFixture) as a test method.

[Category("MyTests")]

Grouping the category inside the tests runner.

Didn't work in Unity 5.5.

[Ignore]

The test is ignored, it's shown as a dashed circle in the runner.

Didn't work in Unity 5.5.

[MaxTime(200)]

The MaxtimeAttribute is used on test methods to specify a maximum time in milliseconds for a test case. If the test case takes longer than the specified time to complete, it is reported as a failure.

[Values(1, 2, 3)]

Avoid.

The ValuesAttribute is used to specify a set of values to be provided for an individual parameter of a parameterized test method. Since NUnit combines the data provided for each parameter into a set of test cases, data must be provided for all parameters if it is provided for any of them.

By default, NUnit creates test cases from all possible combinations of the datapoints provided on parameters - the combinatorial approach. This default may be modified by use of specific attributes on the test method itself.

[Pairwise]

Avoid.

The PairwiseAttribute is used on a test to specify that NUnit should generate test cases in such a way that all possible pairs of values are used. This is a well-known approach for combatting the combinatorial explosion of test cases when more than two features (parameters) are involved.

 

Example:

Using the Combinatorial attribute, the following test would be executed 12 (3x2x2) times. With Pairwise it is executed only enough times so that each possible pair is covered..

 

[Test, Pairwise]

public void MyTest(

    [Values("a", "b", "c")] string a,

    [Values("+", "-")] string b,

    [Values("x", "y")] string c)

{

    Console.WriteLine("{0} {1} {2}", a, b, c);

}

For this test, NUnit currently calls the method seven times, producing the following output:

a - x

b + y

c + x

b - x

a - y

c - y

a + x

Note that this is not the optimal output. The pairs (a, -), (a, x), (+ x), (- x) and (- y) appear twice. NUnit uses a heuristic algorithm to reduce the number of test cases as much as it can. Improvements may be made in the future.

 

Limitations:

When used on a generic method the programmer must ensure that all possible combinations of arguments are valid. When multiple parameters use the same generic type (e.g.: T) this may not be possible and the attribute may generate invalid test cases.

[TestFixtureSetup]

This attribute is used inside a TestFixture to provide a single set of functions that are performed once prior to executing any of the tests in the fixture.

Avoid in favor of explicit Factory and Teardown methods.

[TestFixtureTearDown]

This attribute is used inside a TestFixture to provide a single set of functions that are performed once after all tests are completed.

Avoid in favor of explicit Factory and Teardown methods.

[SetUp]

This attribute is used inside a TestFixture to provide a common set of functions that are performed just before each test method is called. It is also used inside a SetUpFixture, where it provides the same functionality at the level of a namespace or assembly.

Avoid in favor of explicit Factory and Teardown methods.

[TearDown]

This attribute is used inside a TestFixture to provide a common set of functions that are performed after each test method is run. A TestFixture can have only one TearDown method. If more than one is defined the TestFixture will compile successfully, but its tests will not run.

Avoid in favor of explicit Factory and Teardown methods.

[TestCase]

TestCaseAttribute serves the dual purpose of marking a method with parameters as a test method and providing inline data to be used when invoking that method.

When TestCaseAttribute appears multiple times on a method or when other data-providing attributes are used in combination with TestCaseAttribute, the order of the test cases is undefined.

[TestCase(12,3,4)]

[TestCase(12,2,6)]

[TestCase(12,4,3)]

public void DivideTest(int n, int d, int q)

{

  Assert.AreEqual( q, n / d );

}

 

[TestCaseSource]

TestCaseSourceAttribute is used on a parameterized test method to identify the property, method or field that will provide the required arguments. The attribute has two public constructors.

 

TestCaseSourceAttribute(Type sourceType, string sourceName);

TestCaseSourceAttribute(string sourceName);

If sourceType is specified, it represents the class that provides the test cases. It must have a default constructor.

 

If sourceType is not specified, the class containing the test method is used. NUnit will construct it using either the default constructor or - if arguments are provided - the appropriate constructor for those arguments.

 

The sourceName argument represents the name of the source used to provide test cases. It has the following characteristics:

 

It may be a field, property or method.

It may be either an instance or a static member.

It must return an IEnumerable or a type that implements IEnumerable.

The individual items returned by the enumerator must be compatible with the signature of the method on which the attribute appears. The rules for this are described in the next section.

 

static int[] EvenNumbers = new int[] { 2, 4, 6, 8 };

 

[Test, TestCaseSource("EvenNumbers")]

public void TestMethod(int num)

{

    Assert.IsTrue( num % 2 == 0 );

}

 

----------------------

 

[TestFixture]

public class MyTests

{

  [Test,TestCaseSource(typeof(MyFactoryClass),"TestCases")]

  public int DivideTest(int n, int d)

  {

    return n/d;

  }

  ...

}

 

public class MyFactoryClass

{

  public static IEnumerable TestCases

  {

    get

    {

      yield return new TestCaseData( 12, 3 ).Returns( 4 );

      yield return new TestCaseData( 12, 2 ).Returns( 6 );

      yield return new TestCaseData( 12, 4 ).Returns( 3 );

      yield return new TestCaseData( 0, 0 )

        .Throws(typeof(DivideByZeroException))

        .SetName("DivideByZero")

        .SetDescription("An exception is expected");

    }

  } 

}

 

 

Assertions

.AreEqual, .AreNotEqual

Asserts if 2 objects are equal. In case of floats, the comparison is non-exact to take into account floating point inprecision.

.AreSame, .AreNotSame

Assert.AreSame and Assert.AreNotSame test whether the same objects are referenced by the two arguments.

.Contains

Assert.Contains is used to test whether an object is contained in an array or list.

.IsTrue

.IsFalse

.IsNull

.IsNotNull

.IsNaN

Methods that test a specific condition are named for the condition they test and take the value tested as their first argument and, optionally a message as the second.

.IsInstanceOf<T>(object actual)

.IsNotInstanceOf<T>

.IsAssignableFrom<T>

.IsNotAssignableFrom<T>

These methods allow us to make assertions about the type of an object.

.Throws<T>

 

The Assert.Throws method is pretty much in a class by itself. Rather than comparing values, it attempts to invoke a code snippet, represented as a delegate, in order to verify that it throws a particular exception.

Use this instead of Expeced Exception Attribute.

.Pass();

.Fail();

Utility Methods

StringAssert.Contains(string expected, string actual);

StringAssert.StartsWith

StringAssert.EndsWith

StringAssert.AreEqualIgnoringCase

StringAssert

CollectionAssert.AllItemsAreNotNull

CollectionAssert.AllItemsAreUnique

CollectionAssert.AreEqual

CollectionAssert.AreNotEqual

CollectionAssert.Contains

CollectionAssert.DoesNotContain

CollectionAssert.IsEmpty

CollectionAssert.IsNotEmpty

CollectionAssert

FileAssert.AreEqual

FileAssert.AreNotEqual

FileAssert

DirectoryAssert.AreEqual

DirectoryAssert.AreNotEqual

DirectoryAssert.IsEmpty

DirectoryAssert.IsNotEmpty

DirectoryAssert.IsWithin

DirectoryAssert.IsNotWithin

DirectoryAssert

 

Don't use Expected Exception. Instead use Assert.Throws<T> and then StringAssert.Contains on the result.

Avoid all attributes that introduce complication or randomness in the tests.

Don't use the fluent syntax (personal choice) for code consistency.

Don't use theories. Specify most of the tests with [Test], [TestCase] and [TestCaseSource].


If you're finding this article helpful, consider our asset Dialogical on the Unity Asset store for your game dialogues.


Log In:




Comments (0)