Showing posts with label Unit testing. Show all posts
Showing posts with label Unit testing. Show all posts

Thursday, May 2, 2013

Parameterized Test Patterns using Microsoft Pex

We talked before about the difference between unit tests and parameterized unit tests. In this post we will talk about common patterns for writing good parameterized unit tests. Keep in mind that we will use these tests with Microsoft Pex (as an automatic test input generation tool) to get test inputs that trigger all the possible scenarios of the code-under-test.

Before anything, let’s clarify what are the questions we want to answer using the parameterized unit tests. There are  two core questions:

  • What are good scenarios (sequences of method calls) to exercise the code-under-test? (Coverage)
  • What are good assertions that can be stated easily without re-implementing the algorithm? (Verification)

A parameterized unit test is only useful if it provides answers for both questions:

  • Without sufficient coverage, i.e. if the scenario is too narrow to reach all the code-under-test, the extent of the test is limited.
  • Without sufficient verification of the computed results, i.e. if the test does not contain enough assertions, the test does not check that the code is doing the right thing. All it would check for is that the code-under-test does not crash.

Test Patterns

1- Arrange, Act, Assert

The ’AAA’ (Triple-A) is a well-known pattern for writing unit tests. It applies to parameterized unit tests as well. A parameterized unit test using this patter is organized in three sections:

  • Arrange: set up the unit under test
  • Act: exercise the unit under test, capturing any resulting state
  • Assert: verify the behavior through assertions

An example of this pattern in a traditional unit test:


[Test]
pubic void AddItem()
{
// arrange
var list = new ArrayList();
var item = new object();
// act
list.Add(item);
// assert
Assert.IsTrue(list.Count == 1);
}


An example of this pattern in a parameterized unit test:




[PexMethod]
pubic void AddItem(object item)
{
// arrange
var list = new ArrayList();
// act
list.Add(item);
// assert
Assert.IsTrue(list.Count == 1);
}


2- Assume, Arrange, Act, Assert


This pattern is an extension of the first pattern where an Assumption section is added at the beginning. An assumption restricts possible test inputs, acting as a filter. A parameterized unit test using this pattern is organized in four sections:



  • Assume: assume preconditions over the test inputs

  • Arrange: set up the unit under test

  • Act: exercise the unit under test, capturing any resulting state

  • Assert: verify the behavior through assertions


The following example tests that adding an element to any list increments the Count property. We use an assumption to filter out the case where list is a null reference.




[PexMethod]
void AssumeActAssert(ArrayList list, object item)
{
// assume
PexAssume.IsNotNull(list);
// arrange
var count = list.Count;
// act
list.Add(item);
// assert
Assert.IsTrue(list.Count == count + 1);
}


3- Parameterized Stubs



If the code-under-test already contains many assertion statements that verify its behavior, an effective parameterized unit test might be quite simple in itself, because it can leverage the assertions in the code.



[PexMethod] 
public void Add( [PexAssumeUnderTest]ArrayList list, object item)
{
list.Add(item);


The attribute PexAssumeUnderTest is a short-hand notation to make sure that the parameter is not null, and has exactly the type indicated by its declaration (not a subtype).





4- Observed Values

At any point in the parameterized unit test, if you want to log the value of any variable or parameter, just use
PexObserve.ValueForViewing("Variable Name", var_name);


5- Allowed Exceptions


Traditional unit test frameworks support the concept of expected exception, where a test case or API call is expected to throw an exception. If the test does not throw the exception or throws an exception that does not match the criteria, the execution fails. The same concept applied to parameterized unit tests.



[PexMethod][PexAllowedException(typeof(ArgumentNullException))] 
void Constructor(string value)
{
// throws ArgumentNullException if value is null
var myClass = new MyClass(value);
}


6- State Relation


This pattern applies when an API call causes an internal state change that can be (partially) observed through other API calls. A classic example of such a pattern is the combination of Insert and Contains operation on any collection type:




[PexMethod]
void InsertContains(stringvalue)
{
var list = new List();
list.Add(value);
Assert.IsTrue(list.Contains(value));
}


7- Roundtrip


This pattern applies to an API that transforms its inputs in a reversible way: When the API has a function f and an inverse function f_1, then it should hold that f_1(f(x))=x for all x. A classic example of such pattern is property setters and getters, where the test fails when the setter rejects a particular argument value.




[PexMethod]
void PropertyRoundtrip(string value)
{
// arrange
var target = new MyClass();

// two-way roundtrip
target.Name = value; // calls setter
var roundtripped = target.Name; // calls getter

// assert
Assert.AreEqual(value, roundtripped);
}


Another example is serialization and deserialization of values.



[PexMethod]
void ToStringParseRoundtrip(int value)
{
// two-way roundtrip
string s = value.ToString();
int parsed = int.Parse(s);

// assert Assert.AreEqual(value, parsed);
}


8- Normalized Roundtrip


The Pattern Roundtrip showed how to test a method for which in inverse operation exists. For example, int.Parse is the inverse of int.ToString. This is not the case in the other direction: int.ToString is not exactly the inverse of int.Parse, because the parsing ignores whitespace (some kind of data normalization):




int.Parse(" 5").ToString() == "5";


This pattern is applied when the API has a function f and an inverse function f_1, then it should hold that f_1(f(f_1(x)))=f_1(x) for all x where f_1(x) is defined.




[PexMethod]
void ThreeWayRoundtrip(string value)
{
// ’hello%20world’ <= ’hello world’
var normalized = Uri.EscapeDataString(value);

// ’helloworld’ <= ’hello%20world’
var intermediate = Uri.UnescapeDataString(normalized);

// ’hello%20world’ <= ’hello world’
var roundtripped = Uri.EscapeDataString(intermediate);

// assert
Assert.AreEqual(normalized, roundtripped);
}



9- Reachability



If your test assumptions are so complicated and it is not clear whether there is any test input that fulfills them. You could use PexAssert.ReachEventually("GoalName") wherever in your test to make sure that there is at least one input that reach this point in your test. The goal name have to be passed to the PexAssertReachEventuallyAttribute constructor. A parameterized unit test fails when Pex does not find a way to reach a goal, indicated by calling the PexAssert.Reached method in a parameterized unit test annotated with the PexAssertReachEventuallyAttribute.




[PexMethod]
[PexAssertReachEventually("passed", StopWhenAllReached = true)]
public void ParsingSuccesful(string input)
{
// complicated parsing code
DateTime date;
if (DateTime.TryParse(input, out date))
{
// and we want to see at least one case where parsing is successful.
PexAssert.ReachEventually("passed");
}
}


Multiple goals can be combined in a single parameterized unit test for more advanced scenarios by passing a list of goal identifiers in the constructor of the PexAssertReachEventuallyAttribute. Each goal identifier must be reached and notified in order for the parameterized unit test to succeed.




[PexMethod]
[PexAssertReachEventually("parsed", "y2k", StopWhenAllReached = true)]
public void ParsingSuccesfulWithMoreGoals(string input)
{
// complicated parsing code
DateTime date;
if (DateTime.TryParse(input, out date))
{
// and we want to see at least one case where parsing is successful.
PexAssert.ReachEventually("parsed");
}
if (date.Year == 2000)
{
// we want to see at least one test with the year 2000
PexAssert.ReachEventually("y2k");
}
}


10- Reachable Implication



Implications assert a property when a predicate (condition) is true. Use PexAssert.ImpliesEventually to make an implication that should be true and that should be executed at least once. The test have to be annotated with the PexAssertReachEventuallyAttribute. A parameterized unit test fails when Pex does not find a way to make the predicate of PexAssert.ImpliesEventually evaluates true at least once.




[PexMethod]
[PexAssertReachEventually]
public void ParseImpliesParse(string input)
{
bool value;
// if TryParse succeeds, Parse should succeed too. Also make sure TryParse succeeds at least once
PexAssert.ImpliesEventually( bool.TryParse(input, out value), () => bool.Parse(input) );
}


11- Seed Values to Help Pex


A parameterized unit test needs concrete input data to be executed. Pex's role is to automatically generate relevant input data via code analysis. Sometimes it might be desirable or even necessary to provide manually chosen seed values to Pex to guide the automated code exploration. In effect, Pex will fuzz the provided values in ways that cause alternative execution paths to be taken. The PexArgumentsAttribute can be used to provide primitive data. Each instance of this attribute gives a list of values that must match the parameter types of the parameterized unit test (and in the same parameters order).




[PexMethod]
[PexArguments("var i = 0;", 0)]
[PexArguments("class Foo {}", 12)]
public void ParseTest(string text, int line)
{
var parser = new Parser();
parser.SetLine(line);
var node = parser.Parse(text);

}

Before analyzing the branch conditions in the code, Pex will first execute the parameterized unit test with the provided values. This way, Pex acquires knowledge about the code reachable from a test, and during the subsequence code exploration Pex will try to further increase code coverage by slightly modifying the values to trigger different execution paths. In effect, Pex will fuzz the provided values.



12- Regression Tests



In these tests some we could persist a computed value in the generated test so when the generated test is executed in the future, it verifies that the (possible changed) code-under-test still computes the same value. There are several ways how outputs can be logged. For a single output value, one can use the return value of the parameterized unit test:



[PexMethod]
public int Add(int a, int b)
{
return a + b;
}

Pex will recursively traverse the observable properties and fields of the value and add assertions in the generated test for each one of them:



[Test]
[PexGeneratedBy(typeof(Program))]
public void Add866()
{
int i;
i = this.Add(0, 0);
PexAssert.AreEqual(0, i);
}

For multiple values, use out parameters in the parameterized unit tests



[PexMethod]
public void Add(int a, int b, out int result)
{
result = a + b;
}

Which Pex will use to generate the following



[Test]
[PexGeneratedBy(typeof(Program))]
public void Add13()
{
int i = 0;
this.Add(0, 0, out i);
PexAssert.AreEqual(0, i);
}

If the number of values might be dynamic, you could log these values using PexObserve.Value and observe it later using the PexObserve.ValueAtEndOfTest method:



[PexMethod]
void Add(int a, int b)
{
int result = a * b;
PexObserve.Value("result", result);
}

Friday, October 21, 2011

Asserts in NUnit

Assertions (or asserts for short) are helper methods that can assist us in determining whether a method under test is performing correctly or not. They let us assert conditions, data, and so on. All assertion methods will report failures (that’s when the assertion is false) or errors (that’s when we get an unexpected exception) and report these through the NUnit test runner. when a failure or error occurs, execution of the current test method is aborted. Other Test within the same test fixture will still be run.

Classic Asserts

  • Assert.AreEqual (expected, actual, string message)
    • For floating-point numbers we need to specify the tolerance of the equality.
    • Assert.AreEqual(3.33, 10.0/3.0, 0.01)  // Checks the result but looks only for the first two decimal places.
  • Assert.Less(x, y)     // asserts that x < y
  • Assert.Greater(x, y)      // asserts that x > y
  • Assert.LessOrEqual(x, y)    // asserts that x <= y
  • Assert.GreaterOrEqual(x, y)    // asserts that x >= y
  • Assert.IsNull(object, string message)
  • Assert.IsNotNull(object, string message)
  • Assert.AreSame(expected, actual, string message)
  • Assert.IsTrue(bool condition, string message)
  • Assert.IsFalse(bool condition, string message)
  • Assert.Fail(string message)
    • Fails the test immediately, can be used to mark sections of code that should not be reached.

*message in all previous statements is optional.

Constrain-Based Asserts

These are new assertion style introduced in NUnit 2.4. That new style enable many expectations to be evaluated together in a single assertion:

Assert.That(4, Is.LessThan(5) & Is.GreatThan(0));

  • Assert.That(actual, Is.EqualTo(expected))
  • Assert.That(actual, Is.Not.EqualTo(expected));
  • Assert.That(actual, Is.AtMost(expected));        //equivalent to Assert.LessOrEqual()
  • Assert.That(actual, Is.Atleast(expected));        //equivalent to Assert.GreaterOrEqual()
  • Assert.That(expected, Is.Null);
  • Assert.That(expected, Is.Not.Null);                 //equivalent to Assert.That(expected, !Is.Null);
  • Assert.That(expected, Is.Empty);                   //for collections and strings
  • Assert.That(actual, Is.InstanceOfType(expected));
  • Assert.That(actual, Has.Length(expected));
  • Assert.That(actualCollection, List.Contains(expectedValue));
    • Assert.That({5, 3, 2}, List.contains(2))   //will pass
  • Assert.That(actualCollection, Is.SubsetOf(expectedCollection));
    • Assert.That({5, 3, 2}, Is.SubsetOf({5, 4, 3, 2, 1})
  • Assert.That(actual, Text.StartsWith(expected)); //asserts that the expected string is at the beginning of actual
  • Assert.That(actual, Text.Matches(expected));    //asserts that the expected regular expression string matches actual
  • FileAssert.AreEqual(FileInfo expected, FileInfo actual);
    • FileAssert.AreEqual(String pathToExpected, String PathToActual);

NUnit and Exceptions

Part of your code behavior may be throwing a specific exception in certain cases. If you want to assert that your code throws the exceptions that it designed to throw, you need to tag your test method with attribute: [ExpectedException(typeof(ExpectedException))].

   1:  [TestFixture]


   2:  public class ImportListTest


   3:  {


   4:      [Test]


   5:      [ExpectedException(typeof(ArgumentNullException))]


   6:      public void NullList()


   7:      {


   8:          Class1.ImportList(null);


   9:      }


  10:  }



This test method in now expected to throw an exception [from the call to ImportList(null)]. If it doesn’t, the test will fail. If a different exception is thrown (even a superclass of the one specified), the test fails. The test passes only if the exact exception specified is thrown.



Temporarily ignoring tests



If you wrote the test code first and will start writing code incrementally (something like TDD), you may temporarily ignore tests that you still implementing the code required to pass them. You could just tag these tests with attribute [Ignore(“Optional Message”)] . NUnit will report that these tests were skipped and show a yellow bar in the GUI, so you won’t forget about it later.

Structuring unit tests in NUnit

Our goal in the previous post Introduction to NUnit, was just to introduce the unit testing using NUnit as simple as possible. Now it is the time to elaborate more on NUnit framework, structuring and organizing your test cases. If you examined the test code again:

   1:  using System;


   2:  using NUnit.Framework;


   3:  namespace ClassLibrary1


   4:  {


   5:      [TestFixture]


   6:      public class CmpTest


   7:      {


   8:          [Test]


   9:          public void LargestOf3()


  10:          {


  11:              int[] numbers = new int[] { 8, 9, 7 };


  12:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));


  13:          }


  14:      }


  15:  }



The code is pretty straightforward. The using statement on line 2 brings in the necessary NUnit classes.



Next, we have the class definition on line 6: each class that contains tests must be annotated with a [TestFixture] attribute. The class have to be public, so the test runners can run it. The class must have a public, no-parameter constructor.



Finally, the test class contains individual methods annotated with [Test] attributes. Any public, parameterless method specified with a [Test] attribute will be run automatically by NUnit.



Structuring Unit Tests



As a good object-oriented design concept, a class should be focused on one responsibility and only one. This applies to test fixtures as well. Test fixtures should be focused on verifying behavior in a specific scenario. Its name should reflect this scenario. Tests inside that fixture should test different behaviors within this scenario. Tests should be organized around behaviors, not necessarily individual methods. To keep things readable and clear in the test runner output, favor putting fixture classes under a namespace that includes the name of the class that the fixture are testing.




   1:  namespace solutionName.Test.ShoppingCartTest


   2:  {


   3:      [TestFixture]


   4:      public class EmptyCartFixture


   5:      {


   6:          [Test]


   7:          public void OverallRateIsZero() { }


   8:      }


   9:  }



Categories



NUnit provides an easy way to mark and run individual test and fixtures by using categories. A category is just a name that we define. We can associate different test methods with one or more categories, that enable us to select which categories we want to exclude (or include) when running the tests. A category is specified as an attribute.




   1:  using System;


   2:  using NUnit.Framework;


   3:  namespace ClassLibrary1


   4:  {


   5:      [TestFixture]


   6:      public class CmpTest


   7:      {


   8:          [Test]


   9:          [Category("Short")]


  10:          public void LargestOf3()


  11:          {


  12:              int[] numbers = new int[] { 8, 9, 7 };


  13:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));


  14:          }


  15:   


  16:          [Test]


  17:          [Category("Long")]


  18:          [Category("Fred")]


  19:          public void LargestOf3Alt()


  20:          {


  21:              int[] numbers = new int[3];


  22:              numbers[0] = 1;


  23:              numbers[1] = 1;


  24:              numbers[2] = 1;


  25:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(1));


  26:          }


  27:   


  28:          [SetUp]


  29:          public void LargestOf3Alt2()


  30:          {


  31:              int[] numbers = new int[1];


  32:              numbers[0] = 0;


  33:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(0));


  34:          }


  35:      }


  36:  }



In the GUI, if you excluded “Short” methods from run, only LargestOf3() will be selected and executed.



NUnit3



When categories are used, only the tests in the selected categories will be run. Those tests in categories that are not selected are not reported at all. If no category selected in the GUI, then all methods will be executed unless it is tagged with Explicit attribute. The Explicit attribute causes a test or test fixture to be ignored unless it is explicitly selected for running.



Per-Method Setup and Teardown  We should write our test in order that each test can run independently of other tests; this allows us to run any test at any time in any order. In order to accomplish that we may need to reset things between tests or clean up after a test has run. [Setup] and [TearDown] attributes are used for these tasks.



Per-Fixture Setup and Teardown  If we need to set something up or clean up after the entire test class has run, use [TestFixtureSetup] and [TestFixtureTearDown] for that.



Although setup and teardown methods generally come in pair, they don’t have to do so.



Suppose we need some sort of database connection for each test. Rather than duplicating code in each test method that connects to and disconnects from the database, we could use SetUp and TearDown methods. Since creating the initial connection to the database can be slow, we may want to do that only once before all the tests run by using TestFixtureSetUp.




   1:  [TestFixture]


   2:  public class DBTest


   3:  {


   4:      private SqlConnection dbConn;


   5:              


   6:      [TestFixtureSetUp]


   7:      public void PerFixtureSetup()


   8:      {


   9:          dbConn = new SqlConnection("ConnectionString");


  10:          dbConn.Open();


  11:      }


  12:   


  13:      [SetUp]


  14:      public void PerTestSetup()


  15:      {


  16:          //populate database with test data


  17:      }


  18:   


  19:      [TearDown]


  20:      public void PerTestTearDown()


  21:      {


  22:          // clean up database


  23:      }


  24:   


  25:      [TestFixtureTearDown]


  26:      public void PerFixtureTearDown()


  27:      {


  28:          dbConn.Close();


  29:          dbConn.Dispose();


  30:      }


  31:   


  32:      [Test]


  33:      public void AccountAccess()


  34:      {


  35:          // Uses dbConn


  36:      }


  37:   


  38:      [Test]


  39:      public void EmployeeAccess()


  40:      {


  41:          // Uses dbConn


  42:      }


  43:  }



In this example, here is the methods run sequence: PerFixtureSetup >> PerTestSetup >> AccountAccess >> PerTestTearDown >> PerFixtureTearDown >> PerFixtureSetup >> PerTestSetup >> EmployeeAccess >> PertestTearDown >> PerFixtureTearDown.



In this post we tried to elaborate more on the NUnit framework and how we structure and organize test cases in NUnit.

Introduction to NUnit

What is unit testing?

According to Jeff Canna, unit testing ensures that a particular method of a class successfully performs a set of specific tasks. Each test confirms that a method produces the expected output when given a known input.

What is NUnit? NUnit is an open source framework that facilitates unit testing for all .NET languages. It allows you to build your test cases directly into the code of the project.

How do I get NUnit? Download the appropriate file from here and install it. That’s it !!

Write your code

We will write our code now and let it drive our testing cases and exploration of NUnit. Make a new project, class library that similar to the code below. Below an implementation of a “largest” method that returns the largest number in a list.

   1:  using System;


   2:  namespace ClassLibrary1


   3:  {


   4:      public class Cmp


   5:      {


   6:          public static int Largest(int[] list)


   7:          {            


   8:              int max = Int32.MaxValue;


   9:              for (int index = 0; index < list.Length - 1; index++)


  10:              {


  11:                  if (list[index] > max)


  12:                      max = list[index];


  13:              }


  14:              return max;


  15:          }


  16:      }


  17:  }



Test your code



Now it comes to the testing step. Writing test cases is a big topic to be discussed here. We will try to make our first test as simple as possible because there is much to be tested the first time besides the code itself. First, add reference to NUnit and then write our test cases.




  1. Right click on the references in “Solution Explorer” and click add a reference.


  2. Click on tab “Browse”


  3. Navigate to your NUnit directory and go into the bin subdirectory. For me this directory is in “C:\Program Files (x86)\NUnit 2.5.10\bin\net-2.0\framework”


  4. Select nunit.framework.dll and click OK.



Then add a new class library to the project and add the code below to it. This code uses the NUnit namespace, attributes, Assert, and Is. We will explain all of these in detail in further posts. For now, just build the project.




   1:  using System;


   2:  using NUnit.Framework;


   3:  namespace ClassLibrary1


   4:  {


   5:      [TestFixture]


   6:      public class CmpTest


   7:      {


   8:          [Test]


   9:          public void LargestOf3()


  10:          {


  11:              int[] numbers = new int[] { 8, 9, 7 };


  12:              Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));


  13:          }


  14:      }


  15:  }



Run your tests



Now we have got our code, and our test cases. The next step is to run that test cases to test our code and that is the role of test runners. A test runner knows to look for the [TestFixture] attribute of a class and for the [Test] methods within it. The runner will run the tests, accumulate some statistics on which tests passed and failed, and report the results to you. There are many test runners, you can use the NUnit GUI which is installed by default with NUnit (will be located in the programs menu of the start menu).



Using NUnit GUI



In the NUnit GUI, select File > Open or press Ctrl + O. This would show the Open Project dialog. Browse to the folder which contains the assembly containing your tests and open it.

NUnit1


Now you can test your code by clicking the Run button.


NUnit2


When we run a selected test, the GUI will display a large, colored, status bar. If all the tests pass, the bar is bright green. If any test fails, the bar is red. If any test was skipped, the bar is yellow.



It is obvious that our test case here have been failed. Try to fix the code and run the test again until it succeed Smile