Showing posts with label Unit Testing. Show all posts
Showing posts with label Unit Testing. Show all posts

Thursday, 10 November 2016

Beyond TDD....to BDD?

It's been a while since I posted anything here - I've moved jobs recently so the last few months have been taken up with settling into the new role.

I've been thinking a lot about test-driven development recently and whether it's always the best approach, or if there are variations on it that are better suited to some applications. When I first started using TDD I was writing software to run risk and cost-benefit models, which were generally perfect for a test-driven approach. The calculation could be broken down in sub-calculations, each of which would be implemented by a single method, with related calculations grouped into classes. Each sub-calculation could then be unit tested and whole thing usually worked out beautifully. They were almost textbook cases of when to employ TDD.

Recently I've been developing much more standard line-of-business applications, heavy on CRUD, with a small amount of complex business logic, and doing TDD just feels like going through the motions, with little benefit gained from it.

What I've decided to do is start researching behaviour-driven development (BDD) as I think it will be better suited to the kind of systems I'm developing now. Plus it will be fun to learn something new!

My companion on this adventure is the Manning book BDD In Action, which I'll be reading on my commute to and from work. I'm also going to document my progress right here! It will be an opportunity to order some of my thoughts, plus a great way to measure my progress.

Watch this space for the first instalment!!

Tuesday, 5 January 2016

Testing IoC Containers

Just a quick post now that I'm back from a Christmas break.

One of the tests that I always write in my applications is one to check that my IoC container is configured properly. This is something that is often neglected and I'm not sure why.

It's just as case of writing a test (or tests) to try and resolve every 'entry point' class in your application. For example, in an MVC application you would test that each controller can be resolved. Any dependency that hasn't been registered in the IoC container will then cause a test failure, informing you at compile-time that you have an issue (rather than it rearing its head at runtime).

To take it to the next level of detail you could have a set of tests that verify that each registered depenedency resolves to the correct type, however I've never felt the need to take it this far.

Thursday, 17 December 2015

Fluent Setups for AutoMapper

I've recently been using fluent interfaces quite a lot to make my test methods more readable. I'll go into a bit more detail in future posts, but here I just want to show you an example that I always use in my tests when I'm using AutoMapper.
[TestMethod]
public void Test_Method_With_Normal_Setup()
{
    var entity = new EntityOne();
    var viewModel = new ViewModelOne();
    var mockMappingEngine = new Mock<IMappingEngine>();
    mockMappingEngine.Setup(m => m.Map<EntityOne, ViewModelOne>(entity))
        .Returns(viewModel);

    var component = new BusinessComponent(mockMappingEngine.Object);

    // Some assertion here
}
The Setup line looks a bit messy to me. Adding a 'WithMapping' extension method on Mock<IMappingEngine> can help here.
public static Mock<IMappingEngine> WithMapping<TSource, TDestination>(
        this Mock<IMappingEngine> mockMapper, 
        TSource source, 
        TDestination expectedResult)
{
    mockMapper.Setup(m => m.Map<TSource, TDestination>(source))
        .Returns(expectedResult);

    return mockMapper;
}
The Setup line can now be simplified a bit:
[TestMethod]
public void Test_Method_With_Helper_Setup()
{
    var entity = new EntityOne();
    var viewModel = new ViewModelOne();
    var mockMappingEngine = new Mock<IMappingEngine>();
    mockMappingEngine.WithMapping(entity, viewModel);

    var component = new BusinessComponent(mockMappingEngine.Object);

    // Some assertion here
}
Because the WithMapping extension method returns a Mock<IMappingEngine> calls can be chained together, so if you've got multiple setups this approach can greatly improve the readability of the test method.

Thursday, 10 December 2015

Unit Testing Legacy Code - Examples

Last time I wrote about the difficulties I've encountered unit testing legacy code. Today I'm going to show you a simple example that I used in a presentation at work a while ago. I've changed some of the class names but the general gist is the same.

I used a very simple MVC controller, with just a single action. I chose this controller on purpose due to its simplicity as it allowed me to communicate the core ideas very easily. I'll write about a more complex case at some point in the future.

I started with the following code:
public class ReferralController : BaseController
{
 public ActionResult Referral()
 {
  var viewModel = new ReferralViewModel();
  var entity = StaticEntityProvider.Get();

  viewModel.Reasons = entity.Reasons;

  return View(viewModel);
 }
}
Briefly this action creates a view model, gets an entity using a static method, sets a property on the view model using the retrieved entity, and finally returns the view with the view model.

One immediate problem stopping us from unit testing this method is the use of the static Get() method. A second problem that isn't apparent from this code is in the instantiation of the view model. I am of the firm opinion that view models should contain no behaviour or dependencies whatsoever. They should just contain simple properties with getters and setters. This is because their job is to hold data that can be bound to a UI (in this case an MVC view). That is their responsibility. Anything in addition to that violates the single responsibility principle. However in this application view models routinely contained logic, and for this initial refactoring I wasn't prepared to tackle that just yet.

So my refactoring focused on encapsulating the creation of the view model, and on eliminating the static method call. For the view model creation I created a factory interface as shown below:
public interface IViewModelFactory
{
 TModel Create<TModel>() where TModel : BaseViewModel, new();
}
I used a couple generic constraints because the view models all inherited from a base class and they all had a parameterless constructor. The interface has a very simple implementation:
public class ViewModelFactory : IViewModelFactory
{
 public TModel Create<TModel>() where TModel : BaseViewModel, new()
 {
  return new TModel();
 }
}
I then created a wrapper interface and class for the entity provider:
public interface IEntityProviderWrapper
{
 Entity Get();
}

public class EntityProviderWrapper : IEntityProviderWrapper
{
 public Entity Get()
 {
  return StaticEntityProvider.Get();
 }
}
Finally these interfaces can be injected into the controller as follows:
public class ReferralController : BaseController
{
 private readonly IViewModelFactory _viewModelFactory;
 private readonly IEntityProviderWrapper _entityProvider;

 public QuoteReferralController(IViewModelFactory viewModelFactory, IEntityProviderWrapper entityProvider)
 {
  _viewModelFactory = viewModelFactory;
  _entityProvider = entityProvider;
 }

 public ActionResult QuoteReferral()
 {
  var viewModel = _viewModelFactory.Create<ReferralViewModel>();
  var entity = _entityProvider.Get();

  viewModel.Reasons = entity.Reasons;

  return View(viewModel);
 }
}
I admit that this is an extremely simple example, but these ideas can be extended to much more complicated cases. Anyway we now have a controller for which unit tests can now be written as its dependencies have been isolated and fake implementations can be injected into the controller from the test class. Mission accomplished!

Monday, 7 December 2015

Unit Testing Legacy Code

Adding unit tests to legacy code can be extremely difficult. There are a number of reasons for this, such as:

  • The code base is often added to on lots of separate occasions, usually over many years, which can lead to a lack of consistency in how things are done (e.g. code conventions can change over time, new versions of the language introduce new features, etc.).
  • Lots of different developers, often of widely differing ability, work on the code.
  • The "it's working so we'd better not touch it" mantra. We've all been guilty of this; sometimes if the code is working, we just leave it be, regardless of its quality.
  • Emergency patches are applied with the promise of "we'll come back and do it properly later": of course this never happens.

This can all add up to a code base that is not particularly amenable to unit testing. Classes are often tightly coupled, with little or no use of dependency injection, and liberal use of static methods.

However legacy code is usually the code most in need of unit tests, as they allow developers to carry out refactoring safe in the knowledge that the functionality of the refactored code has remained unchanged.

In order to break this catch-22 there are a few strategies I use when adding unit tests to a legacy code base. The two main ones are:

  • The abstract factory pattern to encapsulate object creation; a factory abstraction can then be injected into the class under test to decouple it from the dependency being created.
  • Simple classes (with interfaces) to wrap static methods; the interface can be injected as above.

The aim is to introduce hook points to the code so units (e.g. a class) can be isolated and therefore unit tested.

I'll walk through a few examples in a future post of where I have applied these patterns to a real code base.