DevOps Zone is brought to you in partnership with:

Software developer and solutions designer of large distributed systems and frameworks. Luis is a DZone MVB and is not an employee of DZone and has posted 7 posts at DZone. You can read more from them at their website. View Full User Profile

Unit Testing 101: Inversion Of Control

04.19.2013
| 11318 views |
  • submit to reddit

Inversion Of Control is one of the most common and widely used techniques for handling class dependencies in software development and could easily be the most important practice in unit testing. Basically, it determines if your code is unit-testable or not. Not just that, but it can also help improve significantly your overall software structure and design. But what is it all about? It is really that important? Hopefully we’ll clear those out on the following lines.

Identifying Class Dependencies

As we mentioned before,  Inversion Of Control is a technique used to handle class dependencies effectively; but, What exactly is a dependency? In real life, for instance, a car needs an engine in order to function; without it, it probably won’t work at all. In programming it is the same thing; when a class needs another one in order to function properly, it has a dependency on it. This is called a class dependency or coupling.

Let’s look at the following code example:

public class UserManager
{
    private Md5PasswordHasher passwordHasher;

    public UserManager()
    {
        this.passwordHasher = new Md5PasswordHasher();
    }

    public void ResetPassword(string userName, string password)
    {
        // Get the user from the database
        User user = DataContext.Users.GetByName(userName);

        string hashedPassword = this.passwordHasher.Hash(password);

        // Set the user new password
        user.Password = hashedPassword;

        // Save the user back to the database.
        DataContext.Users.Update(user);
        DataContext.Commit();
    }

    // More methods...
}

public class Md5PasswordHasher
{
    public string Hash(string plainTextPassword)
    {
        // Hash password using an encryption algorithm...
    }
}

The previous code describes two classes, UserManager and PasswordHasher. We can see how UserManager class initializes a new instance of the PasswordHasher class on its constructor and keeps it as a class-level variable so all methods in the class can use it (line 3). The method we are going to focus on is the ResetPassword method. As you might have already noticed, the line 15 is highlighted. This line makes use of the PasswordHasher instance, hence, marking a strong class dependency between UserManager and PasswordHasher.

Don’t Call Us, We’ll Call You

When a class creates instances of its dependencies, it knows what implementation of that dependency is using and probably how it works. The class is the one controlling its own behavior. By using inversion of control, anyone using that class can specify the concrete implementation of each of the dependencies used by it; this time the class user is the one partially controlling the class behavior (or how it behaves on the parts where it uses those provided dependencies).

Anyways, all of this is quite confusing. Let’s look at an example:

public class UserManager
{
    private IPasswordHasher passwordHasher;

    public UserManager(IPasswordHasher passwordHasher)
    {
        this.passwordHasher = passwordHasher;
    }

    public void ResetPassword(string userName, string password)
    {
        // Get the user from the database
        User user = DataContext.Users.GetByName(userName);

        string hashedPassword = this.passwordHasher.Hash(password);

        // Set the user new password
        user.Password = hashedPassword;

        // Save the user back to the database.
        DataContext.Users.Update(user);
        DataContext.Commit();
    }

    // More methods...
}

public interface IPasswordHasher
{
    string Hash(string plainTextPassword);
}

public class Md5PasswordHasher : IPasswordHasher
{
    public string Hash(string plainTextPassword)
    {
        // Hash password using an encryption algorithm...
    }
}

Inversion of Control is usually implemented by applying a design pattern called the Strategy Pattern (as defined in The Gang Of Four book). This pattern consists on abstracting concrete component and algorithm implementations from the rest of the classes by exposing only an interface they can use; thus making implementations interchangeable at runtime and encapsulate how these implementations work since any class using them should not care about how they work.

The Strategy Pattern

So, in order to achieve this, we need to sort some things out:

  • Abstract an interface from the Md5PasswordHasher class, IPasswordHasher; so anyone can write custom implementations of password hashers (line 28-31).
  • Mark the Md5PasswordHasherclass as an implementation of the IPasswordHasher interface (line 33).
  • Change the type of the password hasher used by UserManager to IPasswordHasher (line 3).
  • Add a new constructor parameter of type IPasswordHasher interface (line 5), which is the instance the UserManager class will use to hash its passwords. This way we delegate the creation of dependencies to the user of the class and allows the user to provide any implementation it wants, allowing it to control how the password is going to be hashed.

This is the very essence of inversion of control: Minimize class coupling. The user of the UserManager class has now control over how passwords are hashed. Password hashing control has been inverted from the class to the user. Here is an example on how we can specify the only dependency of the UserManager class:

IPasswordHasher md5PasswordHasher = new Md5PasswordHasher();
UserManager userManager = new UserManager(md5PasswordHasher);

userManager.ResetPassword("luis.aguilar", "12345");

So, Why is this useful? Well, we can go crazy and create our own hasher implementation to be used by the UserManager class:

// Plain text password hasher:
public class PlainTextPasswordHasher : IPasswordHasher
{
    public string Hash(string plainTextPassword)
    {
        // Let's disable password hashing by returning
        // the plain text password.
        return plainTextPassword;
    }
}

// Usage:
IPasswordHasher plainTextPasswordHasher = new PlainTextPasswordHasher();
UserManager userManager = new UserManager(plainTextPasswordHasher);

// Resulting password will be: 12345.
userManager.ResetPassword("luis.aguilar", "12345");

Conclusion

So, this concludes our article on Inversion of Control. Hopefully with a little more practice, you will be able to start applying this to your code. Of course, the  biggest benefit of this technique is related to unit testing. So, What does it has to do with unit testing? Well, we’re going to see this when we get into type mocking. So, stay tuned!

Published at DZone with permission of Luis Aguilar, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)