Speeding up my unit tests

Published on Apr 28, 2014 by Jamie Munro

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:


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;
}
}
}


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:


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);
}
}
}


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:


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


Becomes:


public FizzBuzzTests()
{
_fizzBuzz = new FizzBuzz();
}


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!

Tags: ASP.NET | Theory | fizzbuzz | tdd | Testing | testing

Related Posts

blog comments powered by Disqus