Showing posts with label NUnit. Show all posts
Showing posts with label NUnit. Show all posts

Monday, April 19, 2010

Unit test all enum values with NUnit

In an older post I demonstrated NUnit's built-in parameterized tests feature. This allows a developer to call a single method to run multiple tests.

Let's say I want to run the test for each value in an enumeration. Using the TestCase attribute, I can write the test like this:

  [TestCase(Powertools.Chainsaw)]
  [TestCase(Powertools.CircularSaw)]
  [TestCase(Powertools.PowerDrill)]
  public void PowerToolsTestExplicit(Powertools p)
  {
      // Do test
  }

Which is fine, but what if I add a new value to the enum? Instead of having to add another attribute to the test, it would be easier to loop over all enum values at runtime. With the TestCaseSource attribute I can do just that.

Within my unit test class I first create a method that returns an IEnumerable (in this case Array) containing the enum values:

  public Array GetPowerTools()
  {
      return Enum.GetValues(typeof(Powertools));
  }

Then I create my unit test and decorate it with the TestCaseSource attribute. The attribute constructor takes one parameter, sourceName, which is the name of the method to call:

  [TestCaseSource("GetPowerTools")]
  public void PowerToolsTestWithIEnumerable(Powertools p)
  {
      // Do test
  }

In either case, this expands my unit tests as expected. The second method is easier to maintain and less likely to allow untested code into the system.

Wednesday, August 19, 2009

Parameterized tests in NUnit

In an earlier post I showed how to pass parameters to test methods using an NUnit RowTest extension. As of version 2.5, the extensions are no longer packaged with the NUnit installer. The good news is that the addition of parameterized tests replaces the RowTest and adds a number of new features as well.

For reference, my previous RowTest looked like this:

[RowTest]
[Row(2, 3)]
[Row(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}

A basic switch to a parameterized test is a matter of dropping the RowTest attribute and replacing each Row attribute with a similarly-formatted TestCase attribute. The new code, which creates two distinct tests as before, looks like this:

[TestCase(2, 3)]
[TestCase(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}

In addition to single parameters you can now specify ranges. If I want to test values of X from 1 to 5, with a Y value of 1, I can do so using the Range and Values attributes, like so:

[Test]
public void AddTwoNumbers(
                    [Range(1, 5)]int x,
                    [Values(1)]int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}        

In the test runner, this shows up as five distinct unit tests


If I specify the range 1-5 for both X and Y, NUnit defaults to creating 25 unique tests. This is the default Combinatorial attribute.


If I wish to use a value from each range only once, I instead mark the test as Sequential

[Test, Sequential]
public void AddTwoNumbers(
                    [Range(1, 5)]int x,
                    [Range(1, 5)]int y)
{
    Assert.AreEqual(x + y, Add(x, y),
        "Add returned incorrect result");
}        

which produces the desired effect

Friday, January 23, 2009

Row tests in NUnit

[Update 8/19/09: As of version 2.5, the extensions are no longer installed with NUnit. See my post on parameterized tests for a replacement.]

File this one under "old features I'm only now learning about." It seems NUnit has had a RowTest extension built in since March of 08...

For example, let's say I have a method called Add that adds two integers and returns the result. (The internals of that method are highly complex and I won't go into details here.) If you wanted to test two positive integers, a unit test would look like this:

[Test]
public void AddTwoPositiveNumbers()
{
    Assert.AreEqual(2 + 3, Add(2, 3), 
        "Add returned incorrect result");
}


To test two negative integers you would historically create a second, nearly identical unit test:

[Test]
public void AddTwoNegativeNumbers()
{
    Assert.AreEqual(-1 + -4, Add(-1, -4), 
        "Add returned incorrect result");
}


For reference, the two tests will appear under the class name when viewed through the NUnit GUI.



Now, these don't seem too bad, but what happens if you needs lots of nearly-identical tests? Or these tests need to perform additional steps? Copy/paste is a bad programming practice, even for unit tests. Fortunately, Nunit provides an extension (under the NUnit.Framework.Extensions namespace not surprisingly) that makes life much easier - the RowTest.

To use, create a single test method with parameters for the varying test data. Decorate the method with a RowTest attribute, and one Row attribute for each test case. The above unit tests can now be replaced by:

[RowTest]
[Row(2, 3)]
[Row(-1, -4)]
public void AddTwoNumbers(int x, int y)
{
    Assert.AreEqual(x + y, Add(x, y), 
        "Add returned incorrect result");
}


Changes to the test set becomes much easier, as does adding new tests. In the GUI, you'll see each Row split out as an individual test beneath the generic test:

Tuesday, September 4, 2007

Upgrading from NUnit 2.2 to 2.4

Until recently, I was running NUnit 2.2.9 on both my work and home computers. This weekend I decided to upgrade my home computer to version 2.4.3. The quick and painless process went as follows:

1) Uninstall v2.2.9
2) Install v2.4.3
3) Open an existing project containing unit tests
4) Updating the references to point to the new assemblies
5) Compile and run...

Well, it all worked except for that last step. At one point, I seem to recall NUnit requiring you to reference nunit.core. Whatever that reason, it's no longer a requirement, and was the cause of the build failure. After removing the reference, everything ran as before.

Constraint-based assertions

One of the most noticeable changes in version 2.4 was the inclusion of constraint-based assertions, similar to some of the mock frameworks available. Previously, you might write assertions like:

Assert.IsTrue(age < 21);
Assert.AreEqual(9, age);

Using constraints, you can now write:

Assert.That(age, Is.LessThan(21));
Assert.That(age, Is.EqualTo(9));

Also, if your test fixture is derived from AssertionHelper, you can shorten the previous lines to:

Expect(age, LessThan(21));
Expect(age, EqualTo(9));

Note: you will need to add using statements for NUnit.Framework.Constraints and NUnit.Framework.SyntaxHelpers. For more examples, including comparisons to the older Assert methods, look for AssertSyntaxTests.cs under the NUnit install directory.