Using Contracts to discover Liskov Substitution Principle Violations in C#

In his book Agile Principles, Patterns, and Practices in C#, Bob Martin talks about using pre- and post-conditions in Eiffel to detect Liskov Substitution Principle violations. At the time he wrote that C# did not have an equivalent feature and he suggested ensuring that unit test coverage was used to ensure the same result. However, that does not ensure that checking for LSP violations are applied consistently. It is up to the developer writing the tests to ensure that they are and that any new derived classes get tested correctly. Contracts, these days, can be applied to the base class and they will automatically be applied to any derived class that is created.

Getting started with Contracts

If you’ve already got Visual Studio set up to check contracts in code then you can skip this section. If you don’t then read on.

1. Install the Code Contracts for .NET extension into Visual Studio.

2. Open Visual Studio and load the solution containing the projects you want to apply contracts to.

3. Open the properties for the project and you’ll see a new tab in the project properties window called “Code Contracts”

4. Make sure that the “Perform Runtime Contract Checking” and “Perform Static Contract Checking” boxes are checked. For the moment the other options can be left at their default values. Only apply these to the debug build. It will slow down the application while it is running as each time a method with contract conditions is called it will be performing runtime checks.

Visual Studio Project Properties

You are now ready to see code contract issues in Visual Studio.

For more information on code contracts head over to Microsoft Research’s page on Contracts.

Setting up the Contract

Using the Rectangle/Square example from Bob Martin’s book Agile Principles, Patterns and Practices in C# here is the code with contracts added:

public class Rectangle
{
    private int _width;
    private int _height;
    public virtual int Width
    {
        get { return _width; }
        set
        {
            Contract.Requires(value >= 0);
            Contract.Ensures(Width == value);
            Contract.Ensures(Height == Contract.OldValue(Height));
            _width = value;
        }
    }

    public virtual int Height
    {
        get { return _height; }
        set
        {
            Contract.Requires(value >= 0);
            Contract.Ensures(Height == value);
            Contract.Ensures(Width == Contract.OldValue(Width));
            _height = value;
        }
    }
    public int Area { get { return Width * Height; } }
}

public class Square : Rectangle
{
    public override int Width
    {
        get { return base.Width; }
        set
        {
            base.Width = value;
            base.Height = value;
        }
    }

    public override int Height
    {
        get { return base.Height; }
        set
        {
            base.Height = value;
            base.Width = value;
        }
    }
}

The Square class is in violation of the LSP because it changes the behaviour of the Width and Height setters. To any user of Rectangle that doesn’t know about squares it is quite understandable that they’d assume that setting the Height left the Width alone and vice versa. So if they were given a square and they attempted to set the width and height to different values then they’d get a result from Area that was inconsistent with their expectation and if they set Height then queried Width they may be somewhat surprised at the result.

But there are now contracts in place on the Rectangle class and as such they are enforced on Square as well. “Contracts are inherited along the same subtyping relation that the type system enforces.” (from he Code Contracts User Manual). This means that any class that has contracts will have those contracts enforced in any derived class as well.

While some contracts can be detected at compile time, others will still need to be activated through a unit test or will be detected at runtime. Be aware, if you’ve never used contracts before that the contract analysis can appear in the error and output windows a few seconds after the compiler has completed.

Consider this test:

[Test]
public void TestSquare()
{
    var r = new Square();
    r.Width = 10;

    Assert.AreEqual(10, r.Height);
}

When the test runner gets to this test it will fail. Not because the underlying code is wrong (it will set Height to be equal to Width), but because the method violates the constraints of the base class.

The contract says that when the base class changes the Width the Height remains the same and vice versa.

So, despite the fact that the unit tests were not explicitly testing for an LSP violation in Square, the contract system sprung up and highlighted the issue causing the test to fail.

 

Loading coffeescript unit tests from separate files

In my previous post I showed how to create unit tests for coffeescript. I also included a link to Eli Thompson’s coffeescript unit testing runner which allows you to easily gather all the .coffee files and the unit tests together in one place thus allowing you to keep your unit tests in separate files (rather than in-lining it in the test-runner as I showed in my previous example).

So far, so good. However, you cannot run this from the local file system as the browser’s security will complain (see the console panel in the screenshot below). The files are loaded using jQuery’s get method.

So, in order to get it to run you need to run it from within the context of a web server. You can use IIS if you are running windows, however for this example, I’m using Linux so I’ll use Apache.

Getting Apache up and running on Linux

To install Apache, in a terminal type:

sudo apt-get install apache2

By default, the newly installed server will serve from the /var/www/ which will contain an index.html already.

In order to create a new site that points to your development environment so that you can run the unit tests locally you need to modify apache.

Start by opening the /etc/apache2/apache2.conf file. (You’ll need to use sudo or run as root in order to write this back as your user won’t have the permission by default.) And add the following to the end of the file:

NameVirtualHost 127.0.0.1:80

This tells Apache that you’ll be creating named web sites on the IP/port specified. This is most useful if you have a server that hosts multiple sites. In our case we are simply using it to create a development site on our local machine. Because we’ve specified the loopback address it won’t be visible outside of the machine it is running on. (More info on NameVirtualHost)

Next we have to create a file in /etc/apache2/sites-available/ directory. As far as I can see, the convention is to use the host name as the name of the file. So a site running a http://www.example.com would have a file of the same name. In this case, as it is a development site running only on localhost I like to name it something along the lines of myproject-localhost so that it is obvious that it is running on the loop back address.

For this example, I’ll create a file called /etc/apache2/sites-available/coffee-tests-localhost with the following content:

<VirtualHost 127.0.0.1:80>
ServerName coffee-tests-localhost
ServerAlias www.coffee-tests-localhost
ServerAdmin colin.mackay@example.com
DocumentRoot /home/colinmackay/hg/blog-and-demos/three-of-a-kind
</VirtualHost>

Since this file is in sites-available that means it is not yet enabled, so the server won’t be serving it up. In order to get it served up there needs to be a duplicate in /etc/apache2/sites-enabled/. You don’t need to create a duplicate in Linux as you can create a symbolic link to the original file. To do that, type the following at a terminal:

cd /etc/apache2/sites-enabled/
sudo ln -s ../sites-available/coffee-tests-localhost .

(Note the dot at the end of the second line!)

Since the host name does not really exist, no DNS will resolve it, this is the point that you need to edit the /etc/hosts file so that your local browser can go to the web site. Add the following line to the hosts file:

127.0.0.1     coffee-tests-localhost

Finally restart the Apache server:

sudo /etc/init.d/apache2 restart

You should now have your web site up and running and displaying the tests to you now.

The running tests

When we go to http://coffee-tests-localhost/tests/test-runner.htmlall the tests now run and there is no error in the browser’s console:

More information

Unit testing with Coffeescript

I’ve recently started  looking at Coffeescript. And to get going with that I’m jumping directly in with unit-testing. I figured that it would be an interesting way to learn the language.

Since coffeescript compiles to javascript, you can use a javascript unit testing framework such as QUnit which can be downloaded from github.

Getting to grips with QUnit

Before we delve into coffeescript part, let’s have a very quick look at QUnit.

In order to run unit tests create an HTML page that will contain the runner. In this page you need to include jQuery, and QUnit (http://code.jquery.com/qunit/git/qunit.css and http://code.jquery.com/qunit/git/qunit.js). The body of your test runner needs to contain elements that QUnit will update during the tests. You also need to include the tests themselves.

I won’t go much further in to QUnit as there is already ample
information about getting going with QUnit over on the jQuery website.

Running coffeescript in the browser

Normally coffeescript is pre-compiled into javascript before being sent to the browser, however it is possible to have the browser compile coffeescript itself. This would not be recommended for production code, but does make life easier for running unit tests as the browser handles the compilation step for you.

You can run coffeescript in the browser by using the script located at http://jashkenas.github.com/coffee-script/extras/coffee-script.js. Then
any subsequent script blocks that are marked with the text/coffeescript type will be compiled on-the-fly. e.g.

<script type="text/coffeescript">
    // Your coffee script code here
</script>

One annoyance I’ve found is that coffeescript relies on “significant whitespace” which means that I’m forced to format my code the way coffeescript likes. In general thats not necessarily a bad thing, especially when you are editing coffeescript files, but with inline script blocks it can be irritating. Your script block may already be indented (and I tend to go for indents of two spaces for HTML files, as opposed to 4 for C#) which coffeescript doesn’t seem to like.

Running some tests

First of all this is what a test looks like in javascript using QUnit.

  <script type="text/javascript">
    $(function(){
        module("My javascript test");

        test("Assert 1 not equal 0", function(){
          ok(1!==0, "One expected to not equal zero");
        });
    });
  &lt/script>

What’s happening above is that the tests run when jQuery is ready. In other words, once the DOM is loaded. (See also: $(document).ready()).

The module method is simply a way of segregating the tests in to groups. All tests that follow a call to module will be grouped into that “module”.

The test happens in the call to test which normally takes a string which is the text to display each time the test is run, and a function containing the actual test. The second test that I have is written in coffee script.

<script type="text/coffeescript">
$(()->
    module("My coffeescript test");
    test("Assert 1 equals 1", ()-> ok(1==1, "One expected to equal one"));
);
</script>

While in coffeescript you don’t need the brackets around the function parameters, I prefer them. Nor do you need the semi-colon to terminate each statment, and again this is personal preference. You’ll see lots of coffeescript that won’t use brackets and semi-colons in the above situations.

Here is the result of the two tests above:

Test 	    runner with passing tests

In both tests above there is a call to ok which asserts that the condition passed in as the first argument is true, if not it fails the test. When a test fails the text in the second parameter of the ok function is displayed. For example, a test designed to deliberately fail:

    test("Assert 2 equals 3", () -> ok(2==3, "2 expected to equal 3"));

And the result in the test runner:

Test runner with failing test

Unit testing with .coffee files

Eli Thompson has an example of how you might want to put together unit tests for a
system written in coffeescript
. The core of his example is to define a list of coffeescript files and a list of tests and have a bit of coffeescript dynamically load them in order to run the tests.

In that example, scriptsToTest contains a list of coffeescript files that contain the code to test, and a list of tests which reference the files that contain the actual tests. The code then loads each coffeescript file, compiles it to javascript and loads it into the DOM so that the browser can execute it. The code that does all the hard work is a rather elegant 9 lines of
coffeescript (not including the declaration of the files involved).

More information

This was a very quick introduction to unit testing with QUnit and
using coffeescript. Here are links to more resources to continue
with:

Mental Block

Today, I seem to be having a mental block while writing some unit tests. I keep writing Assert.AreSame() instead of Assert.AreEqual() and then wondering why tests are failing with bizarre message like “Expected 2, Actual 2”

Just in case anyone else has a day like this I’m going to explain the difference (although mainly as a bit of therapy for myself)

The AreSame() method checks that the expected and the actual reference the exact same “physical” object.

The AreEqual() method checks that the expected and the actual are equal to one another, even if they are not “physically” the same object.

NOTE: This was rescued from the Google Cache. The original was dated Friday, 21st July, 2006.

Tags:

Unit Testing a Static Class

I’ve been trying to find a way to unit test a static class. That is, a class that has no instances. The problem has been that at the end of one test the class’s state could be altered which would mean that at the start of the next test its state would be unknown. This could lead to buggy unit tests.

The solution, I’ve found, is to invoke the type initialiser (sometimes known as the “class initialiser”, “static initialiser”, “static constructor” or “class constructor”) using reflection and ensure that all fields are set up there. That way, each unit test run will be starting the static class with a clean state and it no longer matters what the unit test does.

The code to invoke the type initialiser:

Type staticType = typeof(StaticClassName);
ConstructorInfo ci = staticType.TypeInitializer;
object[] parameters = new object[0];
ci.Invoke(null, parameters);

Tags:

NOTE: This blog entry was rescued from the Google Cache. It was originally dated Monday 7th May, 2007.


There was one comment of note:

If you have a static class with state, then you have a singleton – generally to be avoided, but sometimes unavoidable. One way to think of singletons is as services – they provide a service to your app. Services usually interact with the outside world in some way, so for testing purposes it is useful to be able to switch between a real implementation and a Mock one.

So the trick that I use is to create a singleton service locator class, with a manual switch for changing from Test mode to Normal mode. Fowler calls this the Registry pattern in PoEAA.

5/8/2007 6:38 PM | Steve Campbell

Test Driven Development By Example

Introduction

A lot has been written on the subject of test driven development, and especially on the idea that tests ought to be written first. This is an ideal that I strive for, however, I have a tendency to write the unit tests afterwards.

Some people learn better by example. This article, rather than going in to great length about the principles of test driven development, will walk the reader through the process of building and testing an algorithm by writing the tests first, then changing the method being tested so that it fulfils the tests.

The final code and all the unit tests can be found in the accompanying download. This will require NUnit and Visual Studio 2005.

The specimen problem

I once saw a demo of how to create unit tests up front for a simple method. The method took a positive integer and turned it into roman numerals. So, I’m going to do something similar. I’m going to take an integer and turn it into words, in English. The rules for this may change depending on the language, so if English is not your only language, you may like to try to repeat this exercise in another language.

So, if the integer is 1, the result will be "one". If the integer is 23 the result will be "twenty three" and so on. Also note, I’ll be using British or Commonwealth English. So, for 101 the result in words is "one hundred and one". In American English it would be "one hundred one"

The walk through

The algorithm will also be refined through refactoring techniques. Agile development methodologies, especially eXtreme Programming, suggests that you do the simplest thing possible to get the thing working. So, going by this premise, I’ll work on the solution in bits. First, get it to return "one", then "one" or "two" depending on the input, and so on. Once 21 is reached it should become obvious where some refactoring can take place and so on. The final solution will work for 32 bit integers only.

Getting Started

Visual Studio 2005 has some features that can help with writing the tests first. A test can be written that calls into the class under test and the smart tags will prompt you with an offer to create the message stub for you.

The stub looks like this:

public static string NumberToEnglish(int p)
{
  throw new Exception("The method or operation is not implemented.");
}

If the test is completed to look like this:

[Test]
public void NumberToEnglishShouldReturnOne()
{
  string actual = English.NumberToEnglish(1);
  Assert.AreEqual("one", actual, "Expected the result to be "one"");
}

The test should fail because the stub throws an exception, rather than do what the test expects.

NUnit reports the error like this: "NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnOne : System.Exception : The method or operation is not implemented.".

The next thing to do is to ensure that the code satisfies the demands of the unit test. Agile methodologies, such as XP, say that only the simplest change should be made to satisfy the current requirements. In that case the method being tested will be changed to look like this:

public static string NumberToEnglish(int number)
{
  return "one";
}

At this point the unit tests are re-run and they all work out.

Test "two"

Since the overall requirement is that any integer should be translatable into words, the next test should test that 2 can be translated. The test looks like this:

[Test]
public void NumberToEnglishShouldReturnTwo()
{
  string actual = English.NumberToEnglish(2);
  Assert.AreEqual("two", actual, "Expected the result to be "two"");
}

However, since the method being tested returns "one" regardless of input at this point the test fails:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnTwo :
Expected the result to be "two"
	String lengths are both 3.
	Strings differ at index 0.
	expected: <"two">
	 but was: <"one">
	------------^

Again, keeping with the simplest change principle the code is updated to look like this:

public static string NumberToEnglish(int number)
{
  if (number == 1)
    return "one";
  else
    return "two";
}

The tests now pass.

Test "three" to "twenty"

A third test can now be written. It tests for an input of 3 and an expected return of "three". Naturally, at this point, the test fails. The code is updated again and now looks like this:

public static string NumberToEnglish(int number)
{
  switch (number)
  {
    case 1:
      return "one";
    case 2:
      return "two";
    default:
      return "three";
  }
}

To cut things short the new tests and counter-updates continue like this until the numbers 1 to 20 can be handled. The code will eventually look like this:

public static string NumberToEnglish(int number)
{
  switch (number)
  {
    case 1:
      return "one";
    case 2:
      return "two";
    case 3:
      return "three";
    case 4:
      return "four";
    case 5:
      return "five";
    case 6:
      return "six";
    case 7:
      return "seven";
    case 8:
      return "eight";
    case 9:
      return "nine";
    case 10:
      return "ten";
    case 11:
      return "eleven";
    case 12:
      return "twelve";
    case 13:
      return "thirteen";
    case 14:
      return "fourteen";
    case 15:
      return "fifteen";
    case 16:
      return "sixteen";
    case 17:
      return "seventeen";
    case 18:
      return "eighteen";
    case 19:
      return "nineteen";
    default:
      return "twenty";
  }
}

Test "twenty one" to "twenty nine"

At this point it looks like it will be pretty easy to do 21, but a pattern is about to emerge. After the tests for 21 and 22 have been written, the code is refactored to look like this:

public static string NumberToEnglish(int number)
{
  if (number < 20)
    return TranslateOneToNineteen(number);
  if (number == 20)
    return "twenty";
  return string.Concat("twenty ", TranslateOneToNineteen(number - 20));
}

private static string TranslateOneToNineteen(int number)
{
  switch (number)
  {
    case 1:
      return "one";
    case 2:
      return "two";
    case 3:
      return "three";
    case 4:
      return "four";
    case 5:
      return "five";
    case 6:
      return "six";
    case 7:
      return "seven";
    case 8:
      return "eight";
    case 9:
      return "nine";
    case 10:
      return "ten";
    case 11:
      return "eleven";
    case 12:
      return "twelve";
    case 13:
      return "thirteen";
    case 14:
      return "fourteen";
    case 15:
      return "fifteen";
    case 16:
      return "sixteen";
    case 17:
      return "seventeen";
    case 18:
      return "eighteen";
    default:
      return "nineteen";
  }
}

Now all the tests from 1 to 22 pass. 23 to 29 can be assumed to work because it is using well tested logic.

Test "thirty" to "thirty nine"

30 is a different story. The test will fail like this:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnThirty :
Expected the result to be "thirty"
	String lengths differ.  Expected length=6, but was length=10.
	Strings differ at index 1.
	expected: <"thirty">
	 but was: <"twenty ten">
	-------------^

By using the principle of doing the simplest thing that will work. The public method changes to:

public static string NumberToEnglish(int number)
{
  if (number < 20)
    return TranslateOneToNineteen(number);
  if (number == 20)
    return "twenty";
  if (number <= 29)
    return string.Concat("twenty ", TranslateOneToNineteen(number - 20));
  return "thirty";
}

Naturally, the test for 31 will fail:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnThirtyOne :
Expected the result to be "thirty one"
	String lengths differ.  Expected length=10, but was length=6.
	Strings differ at index 6.
	expected: <"thirty one">
	 but was: <"thirty">
	------------------^

So the code is changed again. This time to:

public static string NumberToEnglish(int number)
{
  if (number < 20)
    return TranslateOneToNineteen(number);
  if (number == 20)
    return "twenty";
  if (number <= 29)
    return string.Concat("twenty ", TranslateOneToNineteen(number - 20));
  if (number == 30)
    return "thirty";
  return string.Concat("thirty ", TranslateOneToNineteen(number - 30));
}

Test "forty" to "ninety nine"

A test for 40 will fail:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnForty :
Expected the result to be "forty"
	String lengths differ.  Expected length=5, but was length=10.
	Strings differ at index 0.
	expected: <"forty">
	 but was: <"thirty ten">
	------------^

The necessary code change starts to draw out a pattern. Of course, the pattern could have been quite easily predicted, but since this code is being built by the simplest change only rule, the pattern has to emerge before it can be acted upon.

The pattern repeats itself until it gets to 99. By this point the public method looks like this:

public static string NumberToEnglish(int number)
{
  if (number < 20)
    return TranslateOneToNineteen(number);
  int units = number % 10;
  int tens = number / 10;
  string result = "";
  switch (tens)
  {
    case 2:
      result = "twenty";
      break;
    case 3:
      result = "thirty";
      break;
    case 4:
      result = "forty";
      break;
    case 5:
      result = "fifty";
      break;
    case 6:
      result = "sixty";
      break;
    case 7:
      result = "seventy";
      break;
    case 8:
      result = "eighty";
      break;
    default:
      result = "ninety";
      break;
  }
  if (units != 0)
    result = string.Concat(result, " ", TranslateOneToNineteen(units));
  return result;
}

Test "one hundred"

The test for 100 will fail. The failure message is:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnOneHundred :
Expected the result to be "one hundred"
	String lengths differ.  Expected length=11, but was length=6.
	Strings differ at index 0.
	expected: <"one hundred">
	 but was: <"ninety">
	------------^

A quick change to the public method allows the test to pass:

public static string NumberToEnglish(int number)
{
  if (number == 100)
    return "one hundred";

  if (number < 20)
    return TranslateOneToNineteen(number);
  // Remainder omitted for brevity
}

Test "one hundred and one" to "one hundred and ninety nine"

What about 101? That test fails like this:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnOneHundredAndOne :
Expected the result to be "one hundred and one"
	String lengths differ.  Expected length=19, but was length=10.
	Strings differ at index 0.
	expected: <"one hundred and one">
	 but was: <"ninety one">
	------------^

At this point it should be easy to see that some of the work that has been done previously can be re-used with a small amount of refactoring. First refactor most of the body of the public method into a class called TranslateOneToNinetyNine. Then re-test to ensure that the refactoring process hasn’t introduced any new problems.

In Visual Studio 2005 it is very easy to highlight some code and extract it into a new method, thus allowing it to be reused by being called from multiple places.

Now the public method looks like the following and all previously successful tests continue to be successful

public static string NumberToEnglish(int number)
{
  if (number == 100)
    return "one hundred";

  return TranslateOneToNinetyNine(number);
}

For numbers from 101 to 199 the pattern is "one hundred and X" where X is the result of the translation between 1 and 99. Because it would take too long to write all those tests, it is possible to write just the edge cases and one or two samples from the middle of the range. That should give enough confidence to continue onwards. In this case, the tests are for 101, 115, 155 and 199.

The code is then re-written to support those tests:

public static string NumberToEnglish(int number)
{
  if (number < 100)
    return TranslateOneToNinetyNine(number);
  if (number == 100)
    return "one hundred";

  string result = string.Concat("one hundred and ",
    TranslateOneToNinetyNine(number - 100));

  return result;
}

Test "two hundred"

The next test to write is for 200. Naturally, this test will fail at this point as the code doesn’t support it. The test looks like this:

[Test]
public void NumberToEnglishShouldReturnTwoHundred()
{
    string actual = English.NumberToEnglish(200);
    Assert.AreEqual("two hundred", actual, "Expected the result to be "two hundred"");
}

The failing test can be predicted. It looks like this:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnTwoHundred :
Expected the result to be "two hundred"
	String lengths differ.  Expected length=11, but was length=22.
	Strings differ at index 0.
	expected: <"two hundred">
	 but was: <"one hundred and ninety">
	------------^

A simple change to the method can get the test passing:

public static string NumberToEnglish(int number)
{
    if (number < 100)
        return TranslateOneToNinetyNine(number);
    if (number == 100)
        return "one hundred";
    if (number == 200)
        return "two hundred";

    string result = string.Concat("one hundred and ",
        TranslateOneToNinetyNine(number - 100));

    return result;
}

Test "two hundred and one" to "two hundred and ninety nine"

Since the next part of the pattern can be seen as very similar to the one hundreds, the two edge cases and a couple of internal cases for the two hundreds are created. Presently, all those tests fail as the method has not been updated to take account of that range of integers.

In order to get those tests working the code is refactored like this:

public static string NumberToEnglish(int number)
{
    if (number < 100)
        return TranslateOneToNinetyNine(number);
    if (number == 100)
        return "one hundred";
    if (number < 200)
        return string.Concat("one hundred and ",
        TranslateOneToNinetyNine(number - 100));
    if (number == 200)
        return "two hundred";

    return string.Concat("two hundred and ",
        TranslateOneToNinetyNine(number - 200));
}

Test "three hundred" to "nine hundred and ninety nine"

From the last change to the method a pattern can be seen to be emerging. The code for dealing with the one hundreds and two hundreds are almost identical. This can be easily changed so that all positive integers between 1 and 999 can be converted into words.

After various unit tests are written to test values from 300 to 999 the code is changed to this:

public static string NumberToEnglish(int number)
{
    if (number < 100)
        return TranslateOneToNinetyNine(number);
    int hundreds = number / 100;
    string result = string.Concat(TranslateOneToNineteen(hundreds),
        " hundred");
    int remainder = number % 100;
    if (remainder == 0)
        return result;

    return string.Concat(result, " and ", TranslateOneToNinetyNine(remainder));
}

Test "one thousand"

As before, the first thing to do is write the test:

[Test]
public void NumberToEnglishShouldReturnOneThousand()
{
    string actual = English.NumberToEnglish(1000);
    Assert.AreEqual("one thousand", actual, "Expected the result to be "one thousand"");
}

Which fails:

NumbersInWords.Test.EnglishTest.NumberToEnglishShouldReturnOneThousand :
Expected the result to be "one thousand"
	String lengths differ.  Expected length=12, but was length=11.
	Strings differ at index 0.
	expected: <"one thousand">
	 but was: <"ten hundred">
	------------^

And the fix:

public static string NumberToEnglish(int number)
{
    if (number == 1000)
        return "one thousand";

    if (number < 100)
        return TranslateOneToNinetyNine(number);
    int hundreds = number / 100;
    string result = string.Concat(TranslateOneToNineteen(hundreds),
        " hundred");
    int remainder = number % 100;
    if (remainder == 0)
        return result;

    return string.Concat(result, " and ", TranslateOneToNinetyNine(remainder));
}

Test "one thousand and one" to "nine thousand nine hundred and ninety nine"

Some forward thinking will reveal that the logic will be similar for the thousands as it was for the hundreds. So, rather than repeat all that in this article, the steps to refactoring the code to work with the range from 101 to 999 can be used similarly with 1001 to 9999. The accompanying download will show all the unit tests.

The final result of this stage is that the public method has been refactored to this:

public static string NumberToEnglish(int number)
{
    if (number < 1000)
        return TranslateOneToNineHundredAndNinetyNine(number);

    int thousands = number / 1000;
    string result = string.Concat(TranslateOneToNineteen(thousands),
        " thousand");
    int remainder = number % 1000;
    if (remainder == 0)
        return result;

    if (remainder < 100)
        return string.Concat(result, " and ",
            TranslateOneToNinetyNine(remainder));

    return string.Concat(result, " ",
        TranslateOneToNineHundredAndNinetyNine(remainder));
}

private static string TranslateOneToNineHundredAndNinetyNine(int number)
{
    if (number < 100)
        return TranslateOneToNinetyNine(number);
    int hundreds = number / 100;
    string result = string.Concat(TranslateOneToNineteen(hundreds),
        " hundred");
    int remainder = number % 100;
    if (remainder == 0)
        return result;

    return string.Concat(result, " and ", TranslateOneToNinetyNine(remainder));
}

Test "ten thousand" to "nine hundred and ninety nine thousand nine hundred and ninety nine"

In the first set of test, that were expected to fail, for the condition that the integer input was a value greater than 9999 actually shows passing tests. This serendipitous circumstance is caused by the TranslateOneToNineteen method being a compatible match for prefixing the "thousand" for a range up to the 19 thousands. Through this code reuse it is possible to get a full range match all the way up to 999999 with only a change to a part of one line of code.

The public method has now changed to:

public static string NumberToEnglish(int number)
{
    if (number < 1000)
        return TranslateOneToNineHundredAndNinetyNine(number);

    int thousands = number / 1000;
    string result = string.Concat(TranslateOneToNineHundredAndNinetyNine(thousands),
        " thousand");
    int remainder = number % 1000;
    if (remainder == 0)
        return result;

    if (remainder < 100)
        return string.Concat(result, " and ",
            TranslateOneToNinetyNine(remainder));

    return string.Concat(result, " ",
        TranslateOneToNineHundredAndNinetyNine(remainder));
}

Test "one million" to "nine hundred and ninety nine million nine hundred and ninety nine thousand nine hundred and ninety nine"

The way the code changes as the number of digits increases should becoming more apparent by now. The amount of code reuse is increasing. The number of necessary tests is decreasing. Confidence is increasing

At the start the first 20 numbers each had their own test. 100% of inputs had a test. From 20 to 99 it was 20 tests. Only 25% of the inputs had tests. From 100 to 999 there were 18 tests. Just 2% of the inputs had tests. From 1000 to 999999 there were, again, just 18 tests. This represents just 2 thousandths of one percent.

At this point the public method has been refactored to look like this:

public class English
{
public static string NumberToEnglish(int number)
{
    if (number < 1000000)
        return TranslateOneToNineHundredAndNinetyNineThousandNineHundredAndNinetyNine(number);

    int millions = number / 1000000;
    string result = string.Concat(TranslateOneToNineHundredAndNinetyNine(millions),
        " million");
    int remainder = number % 1000000;
    if (remainder == 0)
        return result;

    if (remainder < 100)
        return string.Concat(result, " and ",
            TranslateOneToNinetyNine(remainder));

    return string.Concat(result, " ",
        TranslateOneToNineHundredAndNinetyNineThousandNineHundredAndNinetyNine(remainder));
}

private static string TranslateOneToNineHundredAndNinetyNineThousandNineHundredAndNinetyNine(int number)
{
    if (number < 1000)
        return TranslateOneToNineHundredAndNinetyNine(number);

    int thousands = number / 1000;
    string result = string.Concat(TranslateOneToNineHundredAndNinetyNine(thousands),
        " thousand");
    int remainder = number % 1000;
    if (remainder == 0)
        return result;

    if (remainder < 100)
        return string.Concat(result, " and ",
            TranslateOneToNinetyNine(remainder));

    return string.Concat(result, " ",
        TranslateOneToNineHundredAndNinetyNine(remainder));
}

Test "one billion" upwards

The limitations of an integer (Int32) mean that this section reaches the upper limits of 2147483647. Unless an Int64 is used there is no continuation to the trillion range.

Final stages

To this point all positive integers are successfully being translated from an integer into a string of words. At this point, through code reuse, it should be a fairly simple matter to refactor the code to work with negative numbers and zero.

Zero is easy enough. The unit test is put in place:

[Test]
public void NumberToEnglishShouldReturnZero()
{
  string actual = English.NumberToEnglish(0);
  Assert.AreEqual("zero", actual, "Expected the result to be "zero"");
}

And it promptly fails because there is no code to support it. The public method is changed so that it does a quick check at the start:

public static string NumberToEnglish(int number)
{
  if (number == 0)
      return "zero";
  if (number < 1000000000)
      return TranslateOneToNineHundredAndNintyNineMillion...(number);

  int billions = number / 1000000000;
  string result = string.Concat(TranslateOneToNineteen(billions), " billion");

  int remainder = number % 1000000000;
  if (remainder == 0)
    return result;

  if (remainder < 100)
    return string.Concat(result, " and ", TranslateOneToNinetyNine(remainder));

  return string.Concat(result, " ",
    TranslateOneToNineHundredAndNintyNineMillion...(remainder));
}

Now the test passes. Next is to permit negative numbers.

[Test]
public void NumberToEnglishShouldReturnNegativeOne()
{
  string actual = English.NumberToEnglish(-1);
  Assert.AreEqual("negative one", actual, "Expected the result to be "negative one"");
}

This fails so the code is refactored to this:

public static string NumberToEnglish(int number)
{
  if (number == 0)
    return "zero";

  string result = "";
  if (number < 0)
    result = "negative ";

  int absNumber = Math.Abs(number);

  return string.Concat(result,
    TranslateOneToTwoBillion...SixHundredAndFortySeven(absNumber));
  // Method call above contracted for brevity
}

And the test passes. But what about that final edge case? int.MinValue? The test is written but it fails. The reason is thatMath.Abs(int.MinValue) isn’t possible. So, as this is a one off case, the easiest solution is to put in a special case into the public method:

// Special case for int.MinValue.
if (number == int.MinValue)
  return "negative two billion one hundred and forty seven million " +
    "four hundred and eighty three thousand six hundred and forty eight";

Conclusion

This article demonstrates how to unit test and build a piece of code in small increments. The tests continually prove that the developer is on the right path. As the code is built the constant rerunning of existing tests prove that any new enhancements do not break existing code. If, for any reason, it is later found that the code contains a bug, a test can easily be created that exercises that incorrect code and a fix produced.

The full final code is available in the associated download along with a set of NUnit tests.

Downloads

You can download the example code for this article here.

An introduction to mock objects

Colin Mackay presenting Mock Objects (Grok Talk)Sometimes when you are unit testing you might get to a point where you say “That’s too difficult to unit test so I’m just going to leave it”. This is where mock objects come in. Mock objects are stand-in dummy objects that don’t have any functionality behind them, they just return the values to the application that the real object would have returned.

Unit tests are supposed to test isolated bits of code. A single method on a class, or a single public method that calls some private methods on the class. Nothing more than that. Mock objects ensure that if the code you are testing calls something external to the class being tested you don’t have to worry about what the actaul real class does. This has some useful advantages.

When mocks are used the external class is not used, therefore any bugs in the external class do not affect the code being tested. The tests for that other class should pick up the bugs. If the external class is non-deterministic then mock objects can be used to ensure that the unit test received known values repeatedly. It would be insane to provide random values in to a test because it may fail intermittently. If you have a bug that causes the code to fail then knowing the values that cause the failure is necessary. If these are known a new unit test that exercises the failing code can be written so that it can be seen when it is fixed. If it starts to fail again then it will be seen instantly.

There are many unit frameworks out there, for this demo I’m using Rhino Mocks by Ayende Rahien. Other frameworks include NMock2, Easy Mock and Type Mock. Mock object frameworks are not strictly necessary. It is possible to set up a mock object just by implementing the interface of the object to be mocked, however this can take a bit more work.

As a general rule classes that are outside the class under test (CUT) should be mocked. There are some exceptions like extremely simple classes such as data transfer objects, whose sole purpose is to transfer data without any functionality.

If your class interacts with external systems then the access to those external systems can be abstracted out. Then the interaction with the external system can be mocked. In general this kind of abstraction would normally take place anyway when separating the application into its appropriate modules, assemblies, layers or tiers. For example, if your application relies on some configuration setting, a configuration class would be created that knows what should be in the config file for the application, extracts it and transforms it into values the application can use. If the code being tested needs to access a configuration value, a mock configuration object can be supplied and a strictly defined value will be available for the test. This saves tedious setting up of files in advance of the test run. The same can be achieved with database access, web service access and so on. It is also possible to mock out the user interface if the presenter pattern is used.

At the heart of most mock objects is simply that they provide inputs into the code that is being tested.

The most obvious input into a method is the parameters that are passed in. But the fields of a class are also inputs into the method, and calls to methods and properties are inputs into the method. Mock objects ensure that inputs into a method generated by code outwith the class under test are setup specifically by the unit test.

Let’s take the example of a piece of code that calls into a D.A.L (Data Abstraction/Access Layer). This might be mocked for many reasons.

  • The database may not be available because it is yet to be created or the data hasn’t been migrated yet from an older system.
  • The database may be shared among the developers. In this case the state of the database cannot be guaranteed as other developers may be changing it while tests are running.
  • The database may take too long to set up, or the set up process may have some manual steps. In order for unit tests to be used effectively they need to be easy and quick to run. If they are not then their value quickly diminishes as developers will stop running them so frequently.
  • The unit tests are likely to be run in many different environments and the availability or consistency of the database in those environments cannot be guaranteed. Typically each developer will be running the unit tests on their own machine. In a large team there may be dedicated testers who will be running the unit tests. There may be a system such as CruiseControl that will automatically build and run unit tests whenever it detects a change in the source control database.

Mock object frameworks, such as Rhino Mocks, typically work by setting up a series of commands that it expects to be called, then those commands are replayed into the code that is being tested. Once the code under test is completed then the mock framework verifies that the commands were called. If for example an expectation was that method A is called, but wasn’t the Verify process will throw an exception that the unit test framework will use to report a problem. If, on the other hand, the code calls method B, but that wasn’t expected then the mock object framework will throw a slightly different exception to say that B was not expected to be called.

In the demonstration solution there is a somewhat contrived example of how mocks work. The ProductsFactory class needs to call the Dal in order to work out what products should be instantiated. There are two mock objects at work here. One is the Dal itself and the other is the IDataReader. The unit test code shows the mocks being created and the expectations being set up. It then replays the commands and runs the code that is to be tested. Once the code is run it verifies that the methods have been called. In the second test, where multiple products are returned from the factory, the expectations are set up slightly differently. In this case an additional expecation is being set up that demands that the methods are called in a strict order. In the first unit test the methods could have been called in any order, just so long as they were called.

Further reading/watching

 

Follow

Get every new post delivered to your Inbox.

Join 25 other followers