Increasing Testability - Adding Interfaces and Mocks

Introduction

Welcome! In this lesson, we will focus on enhancing testability by using interfaces and mocks. This lesson will guide us through the process of decoupling dependencies, which is crucial for writing effective and reliable tests. By the end of this lesson, we'll understand how to refactor code to make it more testable and how to use the Moq library to create mock objects for testing.

Understanding the Problem

Testing code with tightly coupled dependencies can be challenging. When a class directly depends on external services, such as email or database services, it becomes difficult to isolate the code under test. This can lead to unreliable and non-repeatable tests. For instance, if our OrderProcessor class directly calls an EmailService to send confirmation emails, testing the OrderProcessor without actually sending emails becomes problematic. The goal is to isolate the code under test to ensure that our tests are reliable and repeatable, while not triggering side effects and not depending on logic that isn't being tested directly.

Introducing Interfaces

Interfaces play a crucial role in decoupling dependencies. By defining an interface, we create a contract that different implementations can adhere to. This allows us to substitute real implementations with test doubles, such as mocks or stubs, during testing. For example, instead of directly using an EmailService in our OrderProcessor, we can define an IEmailService interface. This interface can then be implemented by the EmailService class. Here's the EmailService in question:

C#
public class EmailService
{
    public void SendOrderConfirmation(Order order)
    {
        Console.WriteLine("[Sending Email]This should not happen in tests!");
    }
}

This class can be adjusted to adhere to an interface that defines the contract for the relevant class:

C#
public interface IEmailService
{
    void SendOrderConfirmation(Order order);
}

public class EmailService : IEmailService
{
    public void SendOrderConfirmation(Order order)
    {
        Console.WriteLine("[Sending Email]This should not happen in tests!");
    }
}

By using the IEmailService interface, we can easily swap out the real EmailService with a mock during testing, allowing us to test the OrderProcessor without sending actual emails.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal