Using ExtensionMethods with Moq to Make Your Unit Tests More Readable

As you may have noticed from last week’s post I’ve been doing a lot of Unit Testing work recently. The product I’m working on is huge and very complex and this makes Unit Testing (as well as general coding) a real challenge. I’ve decided to write a more technical post this week focusing on a trick I’ve found which I believe really helps improve the quality of your tests.

One of the tools we’re using is Moq, a mocking framework (much like RhinoMocks or NSubstitute (one I’ve not used but comes recommended)).

One of the biggest challenges developers face when creating Unit Tests is maintaining readability as the test grows. Consider the following typical test

[Test]
public void TypicalTestSetup()
{
  // Arrange
  var mock = new Mock<IDataAccess>();
  mock.Setup(x => x.GetIDOfRowWithGuid(It.IsAny<Guid>())).Returns(12);
  mock.Setup(x => x.GetValueFromDatabase()).Returns(1701);
  mock.Setup(x => x.SaveValue(73)).Returns(36);
  var sut = new BusinessLogic(mock.Object); 

  // Act
  var result = sut.DoWork(7);

  // Assert
  Assert.Equals(42, result);
}

As the mock is an object there’s no reason you can’t create ExtensionMethods for them. If I create the following method

 

/// <summary>
/// Sets up the method GetIDOfRowWithGuid to return the value given
/// </summary>
public static void SetupGetIDOfRowWithGuid(this Mock<IDataAccess> mock, int value)
{
  mock.Setup(x => x.GetIDOfRowWithGuid(It.IsAny<Guid>())).Returns(value);
}

 This allows us to call the setup code much more succinctly

mock.SetupGetIDOfRowWithGuid(12);

Personally I also like to return the mock as part of the ExtensionMethod

/// <summary>
/// Sets up the method GetIDOfRowWithGuid to return the value given
/// </summary>
public static Mock<IDataAccess> SetupGetIDOfRowWithGuid(this Mock<IDataAccess> mock, int value)
{
  mock.Setup(x => x.GetIDOfRowWithGuid(It.IsAny<Guid>())).Returns(value);
  return mock;
}

Because this allows you to create more more fluent style setup instructions.

// Arrange
var mock = new Mock<IDataAccess>()
  .SetupGetIDOfRowWithGuid(12)
  .SetupGetValueFromDatabase(1701)
  .SetupSaveValue(73, 36);
var sut = new BusinessLogic(mock.Object);			

This, in my opinion is far more readable, simplifies your setup and can be used to create powerful, reusable setups and verifies.

Have you used ExtensionMethods with mocks? What other tips and tricks do you use to keep your Unit Tests in order?

Starting Unit Testing in a Huge Codebase

Most people agree that Unit Tests are a good idea, and most developers try to write them (with varying degrees of success). But the challenge of creating Unit Tests for existing projects can be incredibly daunting to developers.

Many people may not see the need, if an area of code has been working for quite some time then why introduce tests which will take a lot of time and (if you need to refactor to make them work) introduce risk in an area? When I wrote about the value of Unit Tests back in 2015 I postulated that the value of these small executable is not in finding bugs, it’s in preventing bugs in the future.

Unit Testing, unlike exploratory is not about finding issues with existing code, it’s about reinforcing and documenting (through executable code) exactly how each function, class, and property should behave in particular circumstances. If you understand this then you’ll see that the value of Unit Tests does not diminish with an established solution (even if most of the teething bugs have already been worked out). In fact it makes your existing code bases much easier to safely maintain!

So the question becomes how and where do we start?

I’m currently working on an application which has in excess of five million lines of code in it. Some parts are new and some date back to the project’s inception. Writing a full set of tests for the entire application is a monumental (and I have to admit largely pointless) exercise.

What we need to do is look at the areas which are most in flux. If Unit Tests are a technique for helping to protect our software against unexpected change then the areas where they deliver the most benefit are the areas of code which change frequently.

We’re engineers, not psychics (at least I’m not) so use metrics. Look at your Source Control history and see which classes are subject to frequent change (both bug fixes and feature work applies). Target your Unit Tests here, use the 80:20 rule and target your efforts in the right place. One of my favourite sayings applies here… how do you eat an elephant? A little at a time!

Slowly, little by little the classes which see the most changes will stabilise and you’ll introduce less bugs when expanding them or fixing existing defects.

These are my thoughts, do you have any experiences breaking down huge applications into Unit Tested code? How did you do it?

Why you MUST run your Unit Tests as part of your Build Process

I was browsing StackOverflow the other day (as many geeks are known to do from time to time) and read an answer which describes writing Unit Tests as being like going to the gym. Now, I’m not sure about the final few sentences about finding another job but I do really like the analogy. It’s hard when you start out but the more you do the easier it gets and the more value it adds.

Now, like going to the gym there are couple of fundamentals which if forgotten can undermine everything. Unit Tests don’t require proper warmups or cool downs but they absolutely, definitely, must be run on the build server for their real value to be exploited.

Let me explain why.

Developers are often hackers by nature, we install different things and experiment. That’s what makes us good at our job, it’s also what makes every developer’s computer slightly different so software which runs on one machine could behave very differently on another.

What’s worse, if your developer is in a rush or having a bad day they may completely ‘forget’ to execute the tests before committing code. Now, instead of vigorously tested and proven code being added to source control you’ve got a risk.

Tools like NCrunch help reduce this but the only absolutely foolproof way to ensure that all your tests are executed and passed before deployment is to get your server to run them. Missing out this vital link means you’re opening your build and deployment process up to human error, something you should be very nervous of doing.

Almost all build servers have the capability of running tests so dig out the manual and make sure that when the tests fail, the build fails!