Speeding up my unit tests

S

I hope this isn’t too extremely obvious, but I found that I had to take a step back and re-examine my unit tests to find this simple improvement to speed up my unit tests.

When I wrote about how I’m hooked on test-driven development (TDD), the example in that post was too simple and time savings are not noticed.  However, let’s dive in to something a little deeper where we have a full class to test oppose to a single internal function.

 I’m a big fan of creating classes for stand-alone behaviors.  In this example, I’ll expand upon the FizzBuzz example presented in the earlier post; moving it to its own class though.  Here is the final class that our TDDing led us too:

[code]
using System;

namespace FizzBuzz
{
public class FizzBuzz
{
public object Calculate(int p)
{
if (p < 1)
throw new IndexOutOfRangeException();
if (p % 15 == 0)
return “FizzBuzz”;
if (p % 3 == 0)
return “Fizz”;
if (p % 5 == 0)
return “Buzz”;

return p;
}
}
}
[/code]

Now to our test class.  In the original example we had direct access to the private FizzBuzz function.  However, now we need to instantiate our class and call it in each test.  Here is the updated test class:

[code]
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FizzBuzz.Tests
{
[TestClass]
public class FizzBuzzTests
{
private FizzBuzz _fizzBuzz;

[TestInitialize]
public void Setup()
{
_fizzBuzz = new FizzBuzz();
}

[TestMethod]
public void Given1Expect1()
{
const int expected = 1;
var actual = _fizzBuzz.Calculate(1);
Assert.AreEqual(expected, actual);
}

[TestMethod]
public void Given3ExpectFizz()
{
const string expected = “Fizz”;
var actual = _fizzBuzz.Calculate(3);
Assert.AreEqual(expected, actual);
}

[TestMethod]
public void Given5ExpectBuzz()
{
const string expected = “Buzz”;
var actual = _fizzBuzz.Calculate(5);
Assert.AreEqual(expected, actual);
}

[TestMethod]
public void Given15Expect_FizzBuzz()
{
const string expected = “FizzBuzz”;
var actual = _fizzBuzz.Calculate(15);
Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(IndexOutOfRangeException))]
public void Given0ExpectException()
{
_fizzBuzz.Calculate(0);
}
}
}
[/code]

There are only two differences here from our original code:

  1. We’ve introduced a TestInitialize that news up our FizzBuzz class for each test.
  2. Instead of calling a private function, we are executing the Calculate function of our FizzBuzz class.

As expected all tests are green.

Now these tests are extremely lightweight, so this may not be truly significant, but my 5 tests took 1/10th of a second to complete.

Now to the – now – obvious refactoring.

Why am I using the TestInitialize tag?  This is called at the start of each test.  I don’t think my class needs to be newed up at the start of each test.  Instead, I can new it up once:

This:

[code]
[TestInitialize]
public void Setup()
{
_fizzBuzz = new FizzBuzz();
}
[/code]

Becomes:

[code]
public FizzBuzzTests()
{
_fizzBuzz = new FizzBuzz();
}
[/code]

By moving this to the constructor of the test class, it will only get called once for all tests, instead of once per test.

These tests now take only 1/5th of a second, cutting the time in half.

Like I stated at the onset, this feels extremely obvious, but as I was writing unit tests the TestInitialize seemed like the obvious spot to perform my shared test setup.

It of course is still a great spot to initialize shared data that changes during each test that you want to sure it re-initialized for your next test!

Because these tests don’t do a lot, the savings was minimal.  Where I saw huge gains was when tests were using some sort of Mocking.

The mocking was being initialized for each regardless of whether the mocking needed to be re-setup or the same for each test.

By moving the “static” mocks from the TestInitialize, to the constructor, I saw tests go from 200ms to 20ms.  I was able to lower the test suite overall time from 10 minutes to 2 minutes!

About the author

By Jamie

My Books