Interested in a
Personal Demo ?


Name* :
Please Enter your Name
Company E–Mail* :
Please Enter a Valid Email

Testimonials


"Typemock Isolator enables us to modify our legacy applications without changing the source code."
Christian Mérat, .NET Architect & Developer, GSoft Group
Success stories

PurchaseOptions


US Toll Free
866–895–4680
Outside US
+44–203–150–0293
Get your printable quote
Buy online

 

 

tipUnit-Test Patterns for .NET - Part I

Abstract

This article looks at unit testing patterns and describes the main patterns found in tested .NET code. It also describes the problems with each pattern. We will be using nUnit for our examples. For more information, see nUnit and Test Driven Development. Read the below nUnit tutorial to get more information on Nunit Unit testing.


Introduction

Programmers who have incorporated unit testing into their development process already know its advantages: cleaner code, courage to refactor, and higher speed. Writing tests is easy; it is writing good tests that makes automated unit testing a powerful tool. This article provides some basic testing patterns that help write good tests, although some cases may need special attention. But first we must understand what a good test is. The following is a list of features of a good test:

Isolation:

Tests should test only the code that we plan to test. We should not test underlying classes, which should be checked independently. Failure to test isolated code will lead to a high coupling between tests, and changing a class may cause many unrelated tests to fail. The normal scope is a class, although sometimes it makes more sense to test a cluster of classes that are closely coupled (functionality wise).

Speed:

If running the tests takes too long, then developers are reluctant to run them. Therefore, we should keep our tests as fast as possible.

Self containment:

Tests that rely on external information are prone to fail and require configurations and setups. This leads to test discarding. To make sure that this doesn't happen, all the information required for the tests should be in the tests. For example, instead of relying on an environment variable to be set, we must set it ourselves in the test.

Race safe:

Multiple developers should be able to execute tests at the same time. When a test depends on a shared state, it can lead to the wrong test results. For example, if there is a test that depends on and modifies a database and several developers are running it simultaneously, the data will be corrupted and the test will fail.

Independence:

Tests should not rely on other tests to be run before or after. They must be able to be run alone so that the developer can run a single test at a time.

Well documented:

Good documentation about what the test is doing will help understand the production code. Moreover, many developers don't like to read documentation and prefer to see an example of how to use the code. This is fine, and the tests can be a reference point.

Maintainable:

Tests should be seen as part of the software code even though it doesn't make it to production. As such, it must be maintainable and refactored when needed.

Patterns, Patterns, Patterns

Throughout this article, we will use an example of an Authentication class. As it name suggests, this class is responsible for authentication in our system. Each pattern description is divided into three parts:

  • When to use the patterns - what are the cases in which we will use the pattern
  • How to use the pattern - what are the recommended steps of the pattern
  • Example - example code in C#

We will now delve into the patterns.

Four-Stage Testing Pattern

When should it be used?

This is the normal testing scheme.

How should be it used?

  1. Setup prerequisite objects: Create the scenario of the test (this can be done in the test method or in the [SetUp] and [TestFixtureSetUp] methods).
  2. Call the method being tested.
  3. Evaluate the results.
  4. Tear down the objects.
Example

We want to test the EncodePassword method:

 

public class Authentication

{

private string _key;

public string Key

{

get  {return _key;}

set {_key = value;}

}

public string EncodePassword(string password)

{

// do the encoding

return encoded_password;

}

}

 
This is our test:
 

[TestFixture]

public class TestFixture1

{

Authentication authenticator;

String name;

[SetUp] public void Init()

{

// set up our authenticator and key

authenticator = new Authentication();

authenticator.Key = "TESTKEY";

name = "user";

}

[TearDown] public void End()

{

// finish tests

authenticator.Key = "";

}

[Test] public void Encoding ()

{

// continue specific test set up

String expectedKey = "fwe94t-gft5";

// Call our method

String recivedKey = authenticator.EncodePassword(name);

// Validate that for "user" and "TESTKEY" key we should get our key

Assert.AreEqual(expectedKey,recivedKey);

}

}

 

Test-Exception Pattern

When should it be used?
When we expect our test to raise an exception.

How should it be used?
Use nUnit's [ExpectedException] attribute.

Example

Our EncodePassword method throws an exception if the password is empty:

 

public string EncodePassword(string password)

{

if (password==null || password.Length==0)

{

throw new ValidationException("Password is empty");)

{

// do the encoding

return encoded_password;

}

 

The following code snippet shows an example of how to test exceptions:

 

[Test]

[ExpectedException(ValidationException,"Password is empty")]

public void Encoding ()

{

authenticator.EncodePassword(null);

}

 

We expect our test to throw ValidationException with the "Password is empty" error message.

Inner-Class Test Pattern

When should it be used?
When a protected entity (field or method) needs to be accessed for the test. This can happen in two situations:

  1. When we need to test a protected method or access a protected field.
  2. When we need to override a public or protected method (can be done only if the method is virtual).

 

How should it be used?
Create a new class that extends our tested class.
To test a protected method, add a method in our extended class that calls the protected method (delegation). To override a method, override this method in our extended class.

 

 

Example - Testing a protected method
The following code snippet shows an example of how to test the protected EncodePassword method.