NUNIT

Summary

Introduction

NUnit, like all the other XUnit family of testing frameworks, all provide roughly the same functionality. They allow you to write test code in the same language as your production code, and they provide a collection of test runners (drivers) to automate the process of running tests and reporting results.

The basic approach to using NUnit is:

  1. Create a separate project for testing and add a reference to NUnit.Framework.dll.
  2. Write testing code which is decorated with a series of attributes provided by the NUnit framework.
  3. Use a test driver to invoke the testing code.

NUnit provides two test runners (drivers):  A GUI application called nunit-gui.exe and a console-based application called nunit-console.exe. The GUI application is better for verifying your own code in your development environment while you work on it. The console version is more useful for automated testing environments on your build and integration servers.

Unit testing with NUnit

NUnit is all about running test cases. Recall that a test case is really a combination of specific inputs and expected results. In other words, you must specify the inputs and you must specify the expected output for these inputs. If after running the test, the actual output does not match the expected output, then the test has succeeded and you have discovered an error. If on the other hand, after running the test, the actual output did match the expected output, then the test has failed and you have not discovered any error (the use of succeeded and failed corresponds to the fact that testing is all about finding errors - you succeed when you find errors!)

The above approach of specifying inputs and expected output, and then noting whether the actual output matches the expected output, corresponds in NUnit to assertions. NUnit provides a static object called Assert that provides a series of static methods all of which evaluate to a boolean condition. For example, Assert.IsTrue is used and interpreted as follows:

Assert.IsTrue( obTriangle.IsEquilateral(100,100,100) );

Here you are testing a function called IsEquilateral and supplying three inputs all have the same value. The expected output is true because you are using Assert.IsTrue. When NUnit runs this test, it will invoke IsEquilateral, and if the function returns true (actual output) then the actual output matches the expected output (Assert.IsTrue implies an expected output of true).

NUnit Test Structure

The basic approach is to write a public testing class for each unit you wish to test. The 'unit' may be anything from a simple class to a system component containing tens of classes (i.e., a data access layer). Given that the class is used to test a unit, it serves to 1) create a subset of tests that can be run as a group, and 2) to provide a level of granularity for controlling the lifecycle and context of a test.Public methods within this class are test methods and typically you would have a test method for each test case. The general layout is shown below:

/* Notes
    1. Keep all test code in separate projects but within the same solution. For example, for project
    Triangle, there is another project called TriangleTest
    2. All test projects must references NUNIT.FRAMEWORK.DLL
*/

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;


namespace TriangleTest
{
    /* A test class is a collection of logically grouped tests, and as such must be
    annotated with the [TestFixture] attribute. The test class must be public and has
    a default constructor. It is important to note that the default constructor should
    not have any side-effects as NUnit may construct the class multiple times in when
    running tests */
    [TestFixture]
    public class TriangleCheckerTest
    {
        private User obUser = null;

        /* Each test method must be able to exist and run on its own. Tests should not
        be affected by side effects or state set by other tests, not should they cause
        side effects to occur. In other words, tests should live in a stateless
        environment. This ensures that we are only testing one functional unit at a time
        and that we do not propagate error conditions between tests.

        All this means that whenever a test starts, it should start with a clean initial
        state, and when the test finishes, it should clean up after itself. [Setup] method
        runs before each [Test] method, and [TearDown] method runs after each [Test] method.
        [Setup] usually contains construction or initialization code, whereas [TearDown]
        contains destruction/de-initialization code */

        [SetUp]
        public void Initialize()
        {
            /* Create an object (each [Test] method will get a newly constructed object),
            or initialize a test database to a known state (each [Test] method will get a
            properly initialized database) */

            obUser = new User();
        }

        [TearDown]
        public void DeInitialize()
        {
            /* Dispose of the object or clean up the database, etc. */
            obUser.Dispose()
        }


        /* [TestFixtureSetup] and [TestFixtureTearDown] are similar in concept to [Setup]
        and [TearDown] except that they apply at the test class level rather than at the
        test method level. This means that [TestFixtureSetup] and [TestFixtureTearDown]
        should be used to initializer/deinitialise what ever is required before running
        any test in the test class. Examples include creating/deleting a database schema,
        or reading configuration file entries, etc. (Basically anything that needs to be
        done only once before testing as a whole can begin) */

        [TestFixtureSetup]
        public void InitTesT()
        {
            // Create data base schema for testing
        }

        [TestFixtureTearDown]
        public void DeInit()
        {
            // Delete the testing schema from the database
        }

        /* A test class is a collection of tests. Each test is actually a test method
        which must be annotated with [Test], returns void, and takes no parameters
        Semantically, a [Test] method should really correspond to a test case.

        If all assertions within a [Test] method pass, the test passes. If any assertion
        fails, the test fails. Also all unhanded exceptions are also reported as test
        failures */
        [Test]
        public void IsUserRegistered()
        {
            /* Specify input and expected output, and then run test to see if actual
            output matches the expected output. */

            int nID = 123;
            Assert.AreEqual(obUser.GetUserName(nID), "Yazan"); // Input is nID, expected output is "Yazan"

            /* If an assertion fails, the method does not return and an error is reported
            by NUnit. If a test contains many assertions, any that follow the one that
            failed will not be executed. For this reason, it is best to have one assertion
            per test */

            Assert.IsTrue( ... ); // Should not have this assert
        }

        /* Recall that all unhanded exceptions are also reported as test failures. However,
        it may be that an exception is actually an expected results. The [ExpectedException]
        attribute allows you to treat the exception as an expected results */

        [Test]
        [ExpectedException(typeof(InvalidUserOperation))]
        public void UpdatedUser()
        {
            Assert.IsTrue(obUser.UpdateDatabase());
        }

        /* Test cases that are not yet fully implemented can be ignored by NUnit drivers if
        they the test methods are annotated with [Ignore] */

        [Test]
        [Ignore("Not completed yet")]
        public void DeleteUser()
        {
            // To be implemented
        }

        /* [Explicit] causes a test to be ignore unless explicitly selected for running */
        [Test]
        [Explicit]

        public void InsertUser()
        {
            // ...
        }

        /* Tests can also be categorized into groups for each of testing. The GUI version of NUnit
        has a separate tab for 'Categories' that provides a visual indication of which groups are
        selected */

        [Test]
        [Category("No database access")]

        public void SomeTest()
        {
            // ...
        }
    }
}

NUnit Test Example

The following shows how to test a simple program TriangleChecker which takes side lengths and determines if the sides correspond to an equilateral (all sides equal), isosceles (two sides are equal), or scalene (no sides equal) triangle. TriangleChecker implementation has errors and the unit tests should identify these errors:

// The implementation logic is incorrect and unit tests should identify these errors
public class TraingleChecker
{
    // Examines if all sides are equal
    public bool IsEquilateral(int a, int b, int c)
    {
        if ((a == b) && (b == c))
            return true;
        else
            return false;
    }

    // Examines if two sides are equal
    public bool IsIsosceles(int a, int b, int c)
    {
        if ((a == b) || (a == c) || (b == c))
            return true;
        else
            return false;
    }

    // Examines if no sides are equal
    public bool IsScalene(int a, int b, int c)
    {
        if ((a != b) && (b != c))
            return true;
        else
            return false;
    }
}

[TestFixture]
public class TriangleCheckerTest
{
    private Triangle.TraingleChecker m_obTriangleChecker = null;

    [SetUp]
    public void Initialize()
    {
        m_obTriangleChecker = new TraingleChecker();
    }

    [TearDown]
    public void DeInitialize()
    {
        m_obTriangleChecker = null;
    }

    [Test]
    [Category("Equialteral - Valid")]
    public void ValidEquilaterals()
    {
        // Define input conditions
        int a = 10;
        int b = 10;
        int c = 10;

        // Execute a test case with inputs a, b, and c with an expected output of
        // true (Assert.IsTrue means that we are expecting the output to be true)
        Assert.IsTrue(m_obTriangleChecker.IsEquilateral(a, b, c), "Test message");
    }

    [Test]
    [Category("Equialteral - Valid")]
    public void ValidEquilateralUpperBoundary()
    {
        // Setup inputs
        int a = 255;
        int b = 255;
        int c = 255;

        // Execute a test. The expected result should be true as this is a valid triangle
        Assert.IsTrue(m_obTriangleChecker.IsEquilateral(a, b, c));
    }

    [Test]
    [Category("Equialteral - Valid")]
    public void ValidEquilateralLowertBoundary()
    {
        // Setup inputs
        int a = 1;
        int b = 1;
        int c = 1;

        // Execute a test. The expected result should be true as this is a valid triangle
        Assert.IsTrue(m_obTriangleChecker.IsEquilateral(a, b, c));
    }

    [Test]
    [Category("Equialteral - InValid")]
    public void InValidEquilateralsLowerBoundary()
    {
        // Define input conditions
        int a = 0;
        int b = 0;
        int c = 0;

        // Execute a test. The expected result should be false as this is an invalid triangle
        Assert.IsFalse(m_obTriangleChecker.IsEquilateral(a, b, c));
    }

    [Test]
    [Category("Equialteral - InValid")]
    [ExpectedException(typeof(Exception))]
    public void InValidEquilateralsNegativeBoundary()
    {
        // Define input conditions
        int a = -1;
        int b = -1;
        int c = -1;

        // We attempt to examine if negative values for all three sides would pass an an
        // equilateral triangle. It should generate an exception as there is no such
        // triangle, hence the [ExcpectedException] attribute. The way .NET handles exceptions
        // means that control should immediately pass out of the IsEquilateral method to the
        // calling method, in this case the NUnit test method, which in turh passes out to the
        // NUnit test runner. NUnit examines the exception to see if it is of the expected
        // type and if so passes the test. Otherwise the test fails and the exception is reported.
        // Since control passed to the NUnit runner, the Assert.Fail line should never be called.
        // If Assert.Fail does get called, then IsEquilateral did not generate an exception and
        // Assert.Fail will cause the test to fail.
        m_obTriangleChecker.IsEquilateral(a, b, c);
        Assert.Fail( "Tested for negative values but no exception was thrown" );
    }
}

Unit Testing with NUnit and NMock

Understanding the unit testing problem

Consider the example of a business logic library that uses a data access component to communicate with a database server as shown below:

Although the binding between the business logic library and the data access component is interface-based, the business logic library still needs to be able to access properties and methods on the data access component during unit testing, and that's where the trouble begins: the data access component needs a connection to the database server to work. This means that you need to configure the data access component to open a connection to the right database and you almost certainly need to set up a test instance of the database (you never want to test on a production database!) With SQL Server 2005, setting up a test database is quite manageable, but what if the database server was mainframe-based?

Configuring the DAL is not the only problem. If the DAL is part of the development project, it may not even exist yet, and even if it does, is most likely will be under development with a number of known/unknown bugs. In this case, you risk a possible unit test failure due to bugs in the DAL even if the code under test has no defects.

Enter mock objects

For unit testing with mock objects I use NUnit and NMock, which can be obtained from www.nunit.org and www.nmock.org, respectively. The download for NUnit installs NUnit as a stand-alone application with GUI-based and console-based drivers. The download for NMock however,  consists of an assembly nmock.dll that can be references from testing projects directly.

It is worth noting that NMock uses reflection to create mock implementations of interfaces at run time. To use NMock it is therefore necessary to code against interfaces instead of implementations. As this is already a well-regarded best practice, NMock can help enforce this important design technique.

The following figure shown how NUnit and NMock interact:

A common approach to unit testing with mock objects is:

  1. Create instances of mock objects.

  2. Set state in mock objects.

  3. Set expectations in mock objects.

  4. Invoke domain code with mock objects as parameters.

  5. Verify consistency in mock objects.

This approach the test makes clear what the domain code is expecting from its environment.

Shopping Basket Example

class Basket denotes a basket in an e-commerce application. Note the IOC pattern used within this class:

public interface IShoppingDataAccess
{
    string       GetProductName(int productID);
    int          GetUnitPrice(int productID);
    BasketItem[] LoadBasketItems(Guid basketID);
    void         SaveBasketItems(Guid basketID, BasketItem[] basketItems);
}

public class Basket
{
    private ArrayList             basketItems_;
    private Guid                  basketID_;
    private IShoppingDataAccess   dataAccess_;

    public Basket()
    {
        string typeName                = ConfigurationSettings.AppSettings["IShoppingDataAccessType"];
        Type t                         = Type.GetType(typeName);
        IShoppingDataAccess dataAccess = (IShoppingDataAccess)Activator.CreateInstance(t);

        Initialize(dataAccess);
    }

    public Basket(IShoppingDataAccess dataAccess)
    {
        Initialize(dataAccess);
    }

    public void AddItem(BasketItem item)
    {
        this.basketItems_.Add(item);
    }

    public void Save()
    {
        this.dataAccess_.SaveBasketItems(this.basketID_, (BasketItem[])this.basketItems_.ToArray(typeof(BasketItem)));
    }

    public decimal CalculateSubTotal()
    {
        decimal subTotal = 0;
        foreach(BasketItem item in this.basketItems_)
        {
            subTotal += item.GetPrice();
        }
        return subTotal;
    }

    private void Initialize(IShoppingDataAccess dataAccess)
    {
        this.dataAccess_ = dataAccess;
        this.basketItems_ = new ArrayList();
        this.basketID_ = Guid.NewGuid();
    }
}

class BasketItem denotes a single item within the basket:

public class BasketItem
{
    private decimal unitPrice_;
    private int productID_;
    private int quantity_;
    private IShoppingDataAccess dataAccess_;
    private string productName_;

    public BasketItem(int productID, int quantity)
    {
        string typeName =ConfigurationSettings.AppSettings["IShoppingDataAccessType"];
        Type t = Type.GetType(typeName);
        IShoppingDataAccess dataAccess = (IShoppingDataAccess)Activator.CreateInstance(t);

        Initialize(productID, quantity, dataAccess);
    }

    public BasketItem(int productID, int quantity, IShoppingDataAccess dataAccess)
    {
        Initialize(productID, quantity, dataAccess);
    }

    public decimal UnitPrice
    {
        get{return this.unitPrice_;}
    }

    public int ProductID
    {
        get{return this.productID_;}
        set
        {
            this.productID_ = value;
            this.unitPrice_ =
            this.dataAccess_.GetUnitPrice(this.productID_);
            this.productName_ =
            this.dataAccess_.GetProductName(this.productID_);
        }
    }

    public int Quantity
    {
        get{return this.quantity_;}
        set{this.quantity_ = value;}
    }

    public string ProductName
    {
        get{return this.productName_;}
    }

    public decimal GetPrice()
    {
        return this.unitPrice_ * this.quantity_;
    }

    private void Initialize(int productID, int quantity, IShoppingDataAccess dataAccess)
    {
        this.dataAccess_ = dataAccess;
        this.ProductID = productID;
        this.Quantity = quantity;
    }
}

NMock at work

We start by looking at a very simple unit test which demonstrates how to create a mock instance of the IShoppingDataAccess interface:

// Create a DynamicMock object. This object does not implement the supplied type (IShoppingDataAccess),
// but is an object which contains information (via reflection) about the methods of IShoppingDataAccess
// and can emit an implementation of that interface

DynamicMock mock = new DynamicMock(typeof(IShoppingDataAccess));

// DynamicMock objects use reflection to emit an implementation of the desired type and expose it through
// the MockInstance property. Here the dynamically created implementation of IShoppingDataAccess interface
// is passed to the basket constructor as per the Inversion of Control design pattern

Basket b = new Basket((IShoppingDataAccess)mock.MockInstance);

// b.Save internally calls SaveBasketItems method on its internal IShoppingDataAccess member (a mock).
// As nothing was specified in the setup call, the DynamicMock object emits an empty implementation
// of SaveBasketItems.
// Note: Because SaveBasketItems returns void, we are OK with this default behaviour, otherwise, we
// would have to setup the mock object to so as to know what value to return when SaveBasketItems
// is called

b.Save();

The default behaviour of a mock instance for methods with return values is to return null for every method call that returns a reference type, and to return the default value from every method that returns a value type. This is adequate for void methods but is useless for methods with return values. If you examine the BasketItem constructor you will note that the ProductID property is being set which results in two calls to the IShoppingDataAccess interface. Because both calls return a value, a NullReferenceException would have been thrown by the GetUnitPrice method.

When dealing with methods that return values it becomes necessary to instruct the mock object what to return as shown below:

// Create a mock object
DynamicMock mock = new DynamicMock( typeof(IShoppingDataAccess) );

// Setup results. The following configures GetUnitPrice so that it returns 100 every time it is called.
// GetProductName is also configured to return "Effective C#" every time it is called.
// Note: The first two parameters to SetupResult supply the method name and the return value. The
// third parameter is an array of type that is used to identify which method should be called. This
// is requires because a method may have many overloads, and the array of types is required in order
// to infer the correct method via its unique signature (a method's signature consists of its name,
// and the type and kind of each parameter)

mock.SetupResult( "GetUnitPrice", 100, typeof(int) );
mock.SetupResult( "GetProductName", "Effective C#", typeof(int) );

// Invoke the method under test
BasketItem item = new BaksetItem( 1, 2, (IShoppingDataAccess)mock.MockInstance));
...

The above calls to SetupResult ensures that any call to a configured method will always return a specified value, no matter what parameter was used in the method call. For example, if you try to create two basket items, you would get two BasketItem objects with the same unit price and product name (because BasketItem constructor calls the ProductID property which calls GetUnitPrice and GetProductName, which are configured to return fixed values.) 

NMock solves this problem via the ExpectAndReturn method. This method is similar to the SetupResult method but instead supplies a value rather than a type for the method in question. For example:

// Create a mock object
DynamicMock mock = new DynamicMock( typeof(IShoppingDataAccess) );

// Setup results and expectations
mock.ExpectAndReturn( "GetUnitPrice", 100, 1 );
mock.ExepctAndReturn( "GetProductName", "Effective C#", 1 );
mock.ExpectAndReturn( "GetUnitPrice", 200, 10 );
mock.ExepctAndReturn( "GetProductName", "Effective C++", 10 );

// Create two different basket items
BasketItem item1 = new BaksetItem( 1, 2, (IShoppingDataAccess)mock.MockInstance));
BasketItem item2 = new BaksetItem( 10, 2, (IShoppingDataAccess)mock.MockInstance));

// ...

Note that NMock is expecting only two calls to GetUnitPrice and two calls to GetProductName in the order specified. If any of these methods is called with a parameter value other than what is supplied, or if any of these methods is called in a different order, a VerifyException will be fired. Any extra calls would also result in an exception. In other words, you can use ExpectAndReturn to validate that a method was called the expected number of times, with the expected parameters, and in the expected order. With this approach the unit test not only verifies that the unit returns the correct values, but that it communicates any external dependencies as designed. Therefore, letting the mock object participate in the test this way is a good idea.

Consider the first example which is shown below:

// Create a DynamicMock object
DynamicMock mock = new DynamicMock(typeof(IShoppingDataAccess));

// The dynamically created implementation of IShoppingDataAccess interface is passed to the basket
// constructor as per the Inversion of Control design pattern

Basket b = new Basket((IShoppingDataAccess)mock.MockInstance);

// b.Save internally calls SaveBasketItems method on its internal IShoppingDataAccess member (a mock).
// As nothing was specified in the setup call, the DynamicMock object emits an empty implementation
// of SaveBasketItems.
// Note: Because SaveBasketItems returns void, we are OK with this default behaviour, otherwise, we
// would have to setup the mock object to so as to know what value to return when SaveBasketItems
// is called

b.Save();

In the code above no expectation was set for SaveBasketItem which is called internally by the Save method. You should change this behaviour by setting the Strict property to true. This causes any call that does not have an expectation to throw a VerifyException which will in turn fail the test.

However, when you attempt to set an expectation for SaveBasketItem, you will note that the first parameter is a GUID, which is the ID of the basket. On examination of the Basket class, you will note that the basket ID is not accessible externally. Even though this is a design error (should provide a property to provide access to the ID), this design error is used to illustrate the usage of constraints. Constraints solve the following problem: How can you define an expectation if you do not know the value of a parameter in advance? NMock offers many constraints such as IsEqual(), IsNotEqual(), IsNull(), IsypeOf(), StartsWith(), etc.

For example, the call to set expectations in GetUnitPrice can be done using constraints:

mock.ExpectAndReturn( "GetUnitPrice", 100, 1 );            // Equivalent to ...
mock.ExpectAndReturn( "GetUnitPrice", 100, new IsEqual(1) );

So for SaveBasketItem we can a constraint to instruct the mock object that any GUID value is acceptable:

mock.Expect( "SaveBasketItem", new IsTypeIf(typeof(Guid)), item1 );

Finally, the method Verify() on the mock object can be used to end the test so that NMock verifies that all members were accessed the expected number of times. If a member happens to be accessed fewer times than expected, a VerifyException is thrown.

To summarise then: set the Strict option to true at the beginning, set the required expectations,  and then call the Verify method at the end of test.

Designing for Testability

The Basket class has been designed so that a reference to the data access object can be passed in to the constructor. Usually one would overload the constructor so that you have one constructor in which dependencies can be assigned at run time via the Inversion of Control pattern, and another constructor overload in which these parameters are not included. The first overload would typically be used only for tests, whereas the second overload usually becomes the default and used in production code. So why have this distinction?

With the decoupled approach, units (those that will be tested) communicate with other classes via interfaces. An interface defines methods, properties, indexers and events but does not define constructors. This means that when a class needs to instantiate an interface implementation at run time, it has to make assumptions about the constructor.

Unit-Testing GUI with Mock objects

The key to creating code that can be unit tested is to practice loos coupling.  Loosely coupled code is code that can be easily decomposed into discreet objects / assemblies. If the code is all written as one monolithic ball and you cannot initialize one section of it in isolation from the rest, then your code is tightly and not loosely coupled. Code that is not loosely coupled is difficult to test.

When creating loosely coupled code, it is very helpful to provide interfaces for your key objects. The ideal is to have loosely coupled objects that can be initialized in isolation from one another and that can be accessed through interfaces. A rule of thumb for designing for testability is to ensure that each class performs one, and only one, major function.

A GUI example will help re-enforce the concept of designing classes such that each class performs one, and only one, major function. For example, most dialogs have an OK button that to apply or execute user requests. To properly unit test this code,  you need to ensure that data is transferred from the dialog class that contains the OK button to a separate class that holds the data. This ensure that the class dialog only performs one major function; namely getting data from the user. The dialog class should not store the data or perform operations on that data, otherwise it becomes very hard to test.

Separating data operations from user-input operations requires writing extra code - you have to write two classes, one for the input dialog, and another for holding and performing operations on the data. It is important to emphasize that the code that needs to be tested is the code the holds and performs operations on data, and not code that gets data from the user. When was the last time that a textbox failed to retrieve data (all these controls have already been tested by the supplier).

Mock Objects

Given that we have agreed to decompose a GUI class into a class for retrieving data and another for holding and performing operations on data, the next question would be how to test the class that holds/performs operations on data? The code that holds/performs operations on data needs a way to obtain this data. To promote loose coupling between this class and the GUI class, a mock object will be used to mock the dialog class. Instead of getting data from the user via the dialog box, you will get data from the mock object. If your classes were not loosely coupled, you would not have been able to substitute a mock object for the dialog input form.

Writing Mock Objects for Dialogs

Mock objects are almost always built with interfaces (C# interface keyword).  For input dialogs, you typically want to create an interface that can encapsulate the functionality of that input dialog. The following example illustrates:

The following presents the interface requires to capture information from this dialog:

interface IUserDetails
{
    string FirstName { get; set;}
    string LastName { get; set;}
}

and the User Details dialog box implements the IUserDetails interface as shown:

public partial class UserEntry : Form, IUserDetails
{
    private string strFirstName = String.Empty;
    private string strLastName = String.Empty;

    public UserEntry()
    {
        InitializeComponent();
    }

    #region IUserDetails Members
    public string FirstName
    {
        get { return strFirstName; }
        set { strFirstName = value; }
    }

    public string LastName
    {
        get { return strLastName; }
        set { strLastName = value; }
    }
    #endregion

}

And finally, the second class that will be used to hold and perform operations on data retrieved from the User Details dialog box:

// The data object. This is the code that we want to test!
class UserEntryData
{
    private IUserDetails m_IUserDetails;

    public UserEntryData(IUserDetails i )
    {
        m_IUserDetails = i;
    }

    public string FirstName
    {
        get { return m_IUserDetails.FirstName; }
    }

    public string LastName
    {
        get { return m_IUserDetails.LastName; }
    }
}

The above classes would typically be used as follows:

// Create the User Details dialog (in a a menu or button command)
UserDetails frmDetails = new UserDetails();

// Display dialog box
frmDetails.ShowDialog( this );

// User has dismissed dialog box. Pass data from the dialog box into the data class
UserEntryData data = new UserEntryData( frmDetails );        // UserDetails  implements IUserDetails

The key point here is that constructor for UserEntryData does not care what it gets passes as long as it implements the IUserDetails interface. And instead of passing a UserEntry which is actually a form and hence difficult to test, we will pass a mock object that supports the IUserDetails interface. Now we can write our testing code, which is very simple:

[TestFixture(Description="Test UserDetails Form")]
public class UnitTestingGUI
{
    [Test]
    public void UserName()
    {
        // Create a mock object
        DynamicMock mock = new DynamicMock(typeof(GUI.IUserDetails));

        // Create the data object passing the UserDetails dialog mocl
        GUI.UserEntryData data = new GUI.UserEntryData((GUI.IUserDetails)mock.MockInstance);

        // Setup expectations (NMock expects there properties to be called in this order). Values
        // returned from these properties are Yazan and Diranieh, respectively
        mock.ExpectAndReturn("FirstName", "Yazan");
        mock.ExpectAndReturn("LastName", "Diranieh");

        // Test
        Assert.AreEqual(data.FirstName, "Yazan");
        Assert.AreEqual(data.LastName, "Diranieh");

        mock.Verify();
    }
}

Unit Testing and Class Factories

This section describes a solution to a particular problem that you are most likely to face when creating unit tests. The rules of unit testing specify that you should unit test one class at a time. However, in almost all cases, a given class implementation may depend on other classes. The dependency that concerns us here is that which arises via containment. As discusses previously, the solution is to use mock objects.

Using mock objects works very well if you can pass the contained object to the class under test. However, the situation is more complex if the class you want to test does not expose its dependent classes. Class factories and Inversion of Control come to the rescue.

Scenario

Again, let's continue with the example of a business object (to be tested) which uses a data access object (a contained object) to communicate with a database as shown below:

public interface IDAL
{
    DataSet     ExecuteDataSet( string sConn, string sSQL );
    DataReader  ExecuteDataReader ( string sConn, string sSQL );
}

public class SQLServerDAL : IDAL
{
    /* IDAL implementation */
}

public class Order
{
    private SQLServerDAL     obDAL = null;

    public Order()
    {
        obDAL = new SQLServerDAL();
    }

    ...
}

Class Order contains the SQLServerDAL object. This is an example of composition where class Order is completely responsible for the lifetime of class SQLServerDAL. Class Order does not share its instance of SQLServerDAL with any other class nor does it (class Order) provide any properties to expose its SQLServerDAL instance.

In an ideal unit test, only one method of one class should be tested at a time. In the case of class Order, any test you run may inadvertently end up calling methods on class SQLServerDAL. If you want to do integration testing then this is perfectly acceptably. However, for unit testing you should really use a mock of class SQLServerDAL to ensure that you are only testing methods of class Order. For the current implementation of class Order there is no way to pass a mock object.

Solution One - Use Inversion of Control

This solution involves adjusting the design of class Order to accept an instance of class SQLServerDAL. This approach is referred to as inversion of control where the control over the lifetime SQLServerDAL is now outside the control of class Order. Because we defined and implemented interface IDAL for class SQLServerDAL, we can add this new constructor and pass it either a real or a mock instance of SQLServerDAL. The following code illustrates:

public class Order
{
    private IDAL     obDAL = null;

    // This constructor is used for production code
    public Order()
    {
        obDAL = new SQLServerDAL();
    }


    // This new constructor can now be used to pass real of mock instance of SQLServerDAL  
    public Order(IDAL ob)
    {
        obDAL = ob   
    }

    ...
}

// Pass a real SQLServerDAL object to class Order
Order o1 = new Order( new SQLServerDAL() );

// Pass a mock instance of SQLServerDAL to class Order
DynamicMock mock = new DynamicMock(typeof(IDAL));
Order o2 = new Order( (IDAL)mock.MockInstance );

While this is a perfectly reasonable solution, there might be cases when class Order should really control the lifetime of class SQLServerDAL. For example, class Order may need more than one instance of class SQLServerDAL or it might want to create an instance of SQLServerDAL every time it uses a method. The other solution is to pass a class factory.

Solution Two - Use Class Factories

The term 'class factory' refers to a class whose one and only one purpose is to create classes. The classes created by a class factory often (but not always) have the same type, or derive from a specific class/interface. The following example illustrates:

public interface IDALFactory
{
    IDAL CreateDAL();
}

public class RealSQLServerDALFactory : IDALFactory
{
    // IDALFactory implementation
    public IDAL CreateDAL()
    {
        return new SQLServerDAL();
    }
}

public class MockSQLServerDALFactory : IDALFactory
{
    // IDALFactory implementation
    public IDAL CreateDAL()
    {
        DynamicMock mock = new DynamicMock( typeof( IDAL ) );

        // Build expected results
        Dataset ds = BuildExpectedDataset();
        string sConnectionString = GetTestConnectionString();
        string sSQL = GetTestSQL();
        mock.ExepectAndReturn ("ExecuteDataSet", ds, sConnectionString, sSQL );

        return new SQLServerDAL( (IDAL)mock.MockInstance );
    }
}

IDALFactory is a very simple factory interface that will create instances of classes that implement the IDAL interface. RealSQLServerDALFactory an MockSQLServerDALFactory are two implementations of IDALFactory, with the first one returning a real object (i.e., one that would be used in production), and the other returning a mock object (i.e., one that would be used in unit testing).

With these factory implementation, we can change class Order to accept the class factory interface rather than the IDAL interface:

public class Order
{
    private IDALFactory  obDALFactory = null;
    private IDAL          obDAL         = null;

    // This constructor is used for production code
    public Order()
    {
        obDAL = new SQLServerDAL();
    }


    // This new constructor can now be used to pass a SQLSErverDAL class factory. Whether we create a real
    // or a mock object of SQLServerDAL, depends on the run-time type of the passed-in factory

    public Order(IDALFactory ob)
    {
        obDALFactory = ob;
        obDAL  = obDALFactory.CreateDAL();    // Can be real or mock. See note above
    }

    // Now that Order has full control over the lifetime of SQLServerDAL objects, it can use the factory
    // again and again to create instance of IDAL as required

    public void AdjustOrder()
    {
        IDAL ob = obDALFactory.CreateDAL();
    }

    ...
}

// Pass a factory to create real objects of SQLServerDAL
Order o1 = new Order( new RealSQLServerDALFactory() );

// Pass a factory to create mock objects of SQLServerDAL
Order o2 = new Order( MockSQLServerDALFactory()  );

Example (using class factories)

The following code illustrates the full example:

// Interface to be implemeted by SQLServerDAL
public interface IDAL
{
    DataSet         ExecuteDataSet(string sConn, string sSQL);
    SqlDataReader     ExecuteDataReader(string sConn, string sSQL);
}

// Data access class for SQL Server. Implements IDAL
public class SQLServerDAL : IDAL
{
    // IDAL implementation
   
public DataSet ExecuteDataSet(string sConn, string sSQL)
    {
        // A very generic and simple implementation
       
SqlCommand cmd = new SqlCommand();
        cmd.CommandText = sSQL;
        cmd.CommandType = CommandType.Text;
        cmd.Connection = new SqlConnection(sConn);
        DataSet ds = new DataSet();
        SqlDataAdapter da = new SqlDataAdapter();
        da.Fill(ds);
        return ds;
    }

    public SqlDataReader ExecuteDataReader(string sConn, string sSQL)
    {
        // A very generic and simple implementation
       
SqlCommand cmd = new SqlCommand();
        cmd.CommandText = sSQL;
        cmd.CommandType = CommandType.Text;
        cmd.Connection = new SqlConnection(sConn);
        SqlDataReader reader = cmd.ExecuteReader();
        return reader;
    }
}

// An improvement over class SQLServerDAL. It now has a constructor to accept either
// a real object or a mock object

public class Order_Solution1
{
    private IDAL obDAL = null;

    // This constructor is used for production code. It creates a real instnace of SQLServerDAL
   
public Order_Solution1() { obDAL = new SQLServerDAL(); }
  
    // This new constructor can now be used to pass a real of mock instance of SQLServerDAL.
    // Note the inversion of control, where the client of this class is now responsible for
    // creating this class's instnace of SQLServerDAL

    public Order_Solution1(IDAL ob) { obDAL = ob; }

    // Public interface
   
public void PlaceOrder()
    {
        // Collect data
        // ...

        // Place order with database. Note that even though obDAL.ExecuteDataSet does not actually
        // gets called because obDAL is a mock object, the returned dataset ds contains the data that
        // was set up in the mock, namely one table with two rows

        string sConnection = "Database=AdventureWorks;Server=LAPTOP\\SQLEXPRESS;Integrated Security=SSPI;";
        string sSQL = "select * from HumanResources.JobCandidate";
        obDAL.ExecuteDataSet(sConnection, sSQL);
    }
}

public interface IDALFactory
{
    IDAL CreateDAL();
}

// Implements IDALFactory by creating a real instance of SQLServerDAL class
public class RealSQLServerDAL_Factory : IDALFactory
{
    // IDALFactory implementation
   
public IDAL CreateDAL()
    {
        return new SQLServerDAL();
    }
}

// Implements IDALFactory by creating a mock instance of SQLServerDAL class
public class MockSQLServerDAL_Factory : IDALFactory
{
    // IDALFactory implementation
    public IDAL CreateDAL()
    {
        // Setup mock
       
DataSet dsExpectedData;
        string strConnection, strSQL;
        DynamicMock mock = SetupMockForTest1(out dsExpectedData, out strConnection, out strSQL);

        // Return mock instance
        return (IDAL)mock.MockInstance;
    }

    private NMock.DynamicMock SetupMockForTest1(out DataSet ds, out string s, out string sql)
    {
        // Setup inputs adn expected output
       
s = "Database=AdventureWorks;Server=LAPTOP\\SQLEXPRESS;Integrated Security=SSPI;";
        sql = "select * from HumanResources.JobCandidate";
        ds = new DataSet();
        DataTable dt1 = ds.Tables.Add();
        dt1.Columns.Add("ID", typeof(int));
        dt1.Columns.Add("Name", typeof(string));
        dt1.Rows.Add(new object[] { 1, "yazan" });
        dt1.Rows.Add(new object[] { 2, "diranieh" });

        DynamicMock mock = new DynamicMock(typeof(IDAL));
        mock.ExpectAndReturn( "ExecuteDataSet", ds, new object[] {s, sql } );

        return mock;
    }
}

public class Order_Solution2
{
    private IDALFactory obDALFactory = null;
    private IDAL obDAL = null;

    // This constructor is used for production code. It creates a real instnace of SQLServerDAL
   
public Order_Solution2()  { obDAL = new SQLServerDAL(); }

    // This new constructor can now be used to pass a SQLSErverDAL class factory. Whether we create a real
    // or a mock object of SQLServerDAL, depends on the run-time type of the passed-in factory
   
public Order_Solution2(IDALFactory ob)
    {
        obDALFactory = ob;
        obDAL = ob.CreateDAL();
    }

    // Public interface
   
public void PlaceOrder()
    {
        // Collect data
        // ...

        // Place order with database. Note that even though obDAL.ExecuteDataSet does not actually
        // gets called because obDAL is a mock object, the returned dataset ds contains the data that
        // was set up in the mock, namely one table with two rows

        string sConnection = "Database=AdventureWorks;Server=LAPTOP\\SQLEXPRESS;Integrated Security=SSPI;";
        string sSQL = "select * from HumanResources.JobCandidate";
        obDAL.ExecuteDataSet(sConnection, sSQL);
    }

    public void AdjustOrder()
    {
        // Note how we can create new instances of DAL
       
IDAL o = obDALFactory.CreateDAL();

        // ....
   
}
}

[TestFixture(Description="Tests class factory")]
public class MainTest
{
    private ClassFactory.IDALFactory obDALFactory = null;

    [SetUp]
    public void Init()
    {
        obDALFactory = new MockSQLServerDAL_Factory();
    }

    [TearDown]
   
public void DeInit()
    {
        obDALFactory = null;
    }

    [Test(Description = "Testing solution1")]
    public void TestSolution1()
    {
        // Create a mock instnace of SQL Server DAL and pass to class Order
        string s = "Database=AdventureWorks;Server=LAPTOP\\SQLEXPRESS;Integrated Security=SSPI;";
        string sql = "select * from HumanResources.JobCandidate";
        DataSet ds = new DataSet();
        DataTable dt1 = ds.Tables.Add();
        dt1.Columns.Add("ID", typeof(int));
        dt1.Columns.Add("Name", typeof(string));
        dt1.Rows.Add(new object[] { 1, "yazan" });
        dt1.Rows.Add(new object[] { 2, "diranieh" });
        DynamicMock mock = new DynamicMock(typeof(IDAL));
        mock.ExpectAndReturn( "ExecuteDataSet", ds, new object[] {s, sql } );


        // Run test
       
Order_Solution1 obOrder = new Order_Solution1((IDAL)mock.MockInstance);
        obOrder.PlaceOrder();
        mock.Verify();
    }

    [Test(Description = "Testing solution2")]
   
public void TestSolution2()
    {
        ClassFactory.Order_Solution2 obOrder = new Order_Solution2(obDALFactory);
        obOrder.PlaceOrder();
    }
}