Dependency Injection to the rescue

code-coupling

I am a developer, I believe in unit testing and I write a lot of them. But it was not always the case, mostly because I was working on a highly coupled code base. Whenever I wanted to test a single functionality I had to set up a lot of things (database, configuration files, …) to do so even if this functionality was not linked to these dependencies. It was spaghetti code into a big ball of mud.

Then I discovered the Dependency Injection (DI) pattern and it changed the way I designed my code and it made testing much easier. The DI purpose is to reduce coupling between software components in order to improve maintainability and testability. I created the following piece of code to demonstrate the principle :

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
    public bool HasActivatedNotification { get; set; }
}
 
public class EmailNotifier
{
    public void Notify(User user)
    {
        var message = string.Format("Hello {0} ...", user.Name);
        // Sending email
        // ...
    }
}
 
public class UserRepository
{
    public User GetById(int userId)
    {
        // Fetching information from datasource
        // ...
        return new User { Name = "John", Email = "john@john.com" };
    }
}
 
public class NotificationService
{
    public void NotifyUser(int userId)
    {
        var repository = new UserRepository();
        var user = repository.GetById(userId);
 
        if (user.HasActivatedNotification)
        {
            var notifier = new EmailNotifier();
            notifier.Notify(user);
        }
    }
}

The NotificationService sends an email to a given user if he has activated the notifications. Now if I want to test this logic I will have to set up a datasource for my repository and a mail inbox for the notifier. This is a lot of configuration for a simple piece of logic. This code is highly coupled because the NotifyUser method of my service instantiates its dependencies (the repository and the notifier), this means that the Single Responsibility Principle (SRP) is not respected. I will use the Constructor Injection technique to change the code :

public interface INotifier
{
    void Notify(User user);
}
 
public class EmailNotifier : INotifier
{
    public void Notify(User user)
    {
        var message = string.Format("Hello {0} ...", user.Name);
        // Sending email
        // ...
    }
}
 
public interface IUserRepository
{
    User GetById(int userId);
}
 
public class UserRepository : IUserRepository
{
    public User GetById(int userId)
    {
        // Fetching information from datasource
        // ...
        return new User { Name = "John", Email = "john@john.com" };
    }
}
 
public class NotificationService
{
    public NotificationService(IUserRepository repository, INotifier notifier)
    {
        _repository = repository;
        _notifier = notifier;
    }
 
    private readonly IUserRepository _repository;
    private readonly INotifier _notifier;
 
    public void NotifyUser(int userId)
    {
        var user = _repository.GetById(userId);
 
        if (user.HasActivatedNotification)
        {
            _notifier.Notify(user);
        }
    }
}

The UserRepository and the EmailNotifier are unchanged, they just implement interfaces. Now the NotificationService uses these interfaces as fields that are injected through the constructor. The NotifyUser method can now use these dependencies without having to create them, the code is “cleaner”.

I added interfaces for the repository and the notifier for testing purpose, I can test my service with a fake repository and a fake notifier that do not require heavy configuration :

class MockNotifier : INotifier
{
    public MockNotifier()
    {
        NotifyHasBeenCalled = false;
    }
 
    public bool NotifyHasBeenCalled { get; private set; }
 
    public void Notify(User user)
    {
        NotifyHasBeenCalled = true;
    }
}
 
class MockRepository : IUserRepository
{
    public bool HasValidatedNotification { get; set; }
 
    public User GetById(int userId)
    {
        return new User { HasActivatedNotification = HasValidatedNotification };
    }
}

These two implementations are mocks, it means that they mimic the behavior of concrete classes and are used only for testing purpose. In my MockNotifier I just set a flag to true when the Notify method is called, and the GetById method of the MockRepository returns a User instance with the wanted value for HasActivatedNotification. I created a test class with NFluent to show how it is used :

[TestClass]
public class NotificationServiceTest
{
    private NotificationService _notificationService;
    private MockNotifier _mockNotifier;
    private MockRepository _mockRepository;
 
    [TestInitialize]
    public void TestInit()
    {
        _mockNotifier = new MockNotifier();
        _mockRepository = new MockRepository();
        _notificationService = new NotificationService(_mockRepository, _mockNotifier);
    }
 
    [TestMethod]
    public void NotificationActivated()
    {
        _mockRepository.HasValidatedNotification = true;
        _notificationService.NotifyUser(1);
        Check.That(_mockNotifier.NotifyHasBeenCalled).IsTrue();
    }
 
    [TestMethod]
    public void NotificationDeactivated()
    {
        _mockRepository.HasValidatedNotification = false;
        _notificationService.NotifyUser(1);
        Check.That(_mockNotifier.NotifyHasBeenCalled).IsFalse();
    }
}

I can test the logic of my service without having to configure a datasource with pre-configured users and without checking in a inbox if there is an email or not. Dependency Injection reduces code coupling and makes testing easier even if you have to create dedicated classes for them. You can find more information about DI here and here.

Constructor Injection is a pattern I use because with it I improved the maintainability of my code base with less coupling and more testing, you should try it as well if it’s not the case.

See you next time !

Write clean tests with NFluent

nfluent-logo
NFluent logo

I believe in automated testing. Not only to check that my program works but although as specifications and documentation for my application. When an acceptance test passed you know that the feature is working as it should. Automated tests are also a very good way to document your code and your application, because if the test passed it means that the functionnality is working. And if this functionnality is updated so is the test otherwise it will fail : it is up to date !

At a code level a test let you know how to use the functions/classes you can access and what the return value will be. It is useful when using an external library in your own application. Well, this is a lot of responsibility for a test, so it has to be clear, concise and most of all understandable when read. This is not an easy task but there are some tools that can help you, one of them is NFluent.

Smooth your .NET TDD experience with NFluent! NFluent is an ergonomic assertion library which aims to fluent your .NET TDD experience (based on simple Check.That() assertion statements). NFluent aims your tests to be fluent to write (with a super-duper-happy ‘dot’ auto-completion experience), fluent to read (i.e. as close as possible to plain English. – NFluent team on GitHub.

I used this .NET library for a few months now and I must admit that I just love it ! I just can’t see myself writing unit tests without it, they are easier to write and easier to read. There are a lot of built-in functions based on the type of the value that is checked :

[TestClass]
public class NFluentExamples
{
    [TestMethod]
    public void NFluent_Integer_Examples()
    {
        var sum = Calculator.Add(5, 9);
        Check.That(sum).IsEqualTo(14);
        Check.That(sum).IsNotZero();
        Check.That(sum).IsPositive();
        Check.That(sum).IsLessThan(20);
        Check.That(sum).IsGreaterThan(10);
    }
 
    [TestMethod]
    public void NFluent_String_Examples()
    {
        const string name = "John Doe";
        Check.That(name).IsNotEmpty();
        Check.That(name).IsNotEqualTo("Jane Doe");
        Check.That(name).Contains("John", "Doe");
    }
}

It is also possible to chain the checks the following way  :

int? one = 1;
Check.That(one).HasAValue().Which.IsPositive().And.IsEqualTo(1);

In my last blog post I wrote about exception testing, this is how it is done with NFluent :

[TestMethod]
public void NFluentTest()
{
    Check.ThatCode(() => ClassToTest.IsAQuestion(null)).Throws<NullReferenceException>();
}

You can find a lot more relevant examples on the project website.

Beside making you write cleaner and more readable tests, @NFluent is free, easy to install, open-source and comptatible with your favorite testing frameworks. It is hard to find an excuse for not using it !

NFluent can help you having meaningful tests that become documentation for your application and your public APIs.

See you next time !

Are you a software Boy Scout ?

boy-scout

If you are a developer like me, you probably worked on a legacy code based application. If not, don’t worry (or do) it will certainly happen… We all know a project that we fear to open because it is just a huge mess without a single test and nobody really understand how it works, it just does. Every software team has to work in order to prevent the effects of technical debt.

Refactoring a whole application to make the code “cleaner” can take an enormous amount of time, it can be weeks or sometimes months, depending on the project size and complexity. Some organization will incorporate refactoring phases during the development life-cycle. But since during these periods, the team does not provide any new features (i.e. no value), having these refactoring phases is a hard sell. Time to become a Boy Scout then !

What the boys scouts have to do with software development ? The answer is found in their rule :

“Always leave the campground cleaner than you found it.”

This simple rule can be applied to code and especially legacy code, and it becomes :

“Leave the code better than you found it.”

I present you the Boy Scout Rule (BSR) of programming. Making the code “cleaner” can be done at any moment, and it can be done piece by piece, no need to wait for a “Big Bang Refactoring” phase.

If you have a legacy project it is likely that you will have some improvements or bug fixing to do in it. This is the perfect time to embrace the boy scout philosophy. Of course after your passage the application will still be legacy but a bit less, and the next time you will improve it again. The code will become better with time and one day you’ll stop considering the project as a legacy one.

For example it is possible to rename a variable with a more meaningful name. Given the following code to calculate a triangle area :

var res = b / 2 * h

After the BSR applied :

var triangleArea = base / 2 * height

This is not much but it will help the next developer (maybe you) to understand the code and its purpose. And next time you will see that this piece of code is duplicate in several parts of the code. Time to create a method then :

public int CalculateTriangleArea(int base, int height)
{
    return base / 2 * height;
}

You now have a method that can replace your duplicate code and that can be easily tested with your favorite automated testing framework ! I know that this example is really simple but I’m sure you’ll find these kinds of easy “cleaning” in your applications.

There is a type of code refactoring I often use to make my code more understandable and to ease maintainability : moving repeated magic number value into a single constant variable. For example, a few years back, the french VAT was equal to 19.6% and now it is 20%. I let you imagine the pain it could have been to change every “19.6” in some projects where it could have been far easier to use a single constant with a meaningful name.

There are a lot of refactoring techniques to improve your code base, Martin Fowler gives you a list of some of them here.

A software craftsman does not fear legacy code, by following the Boy Scout Rule he will improve his projects.

See you next time !