Quantcast
Viewing latest article 1
Browse Latest Browse All 5

Legacy Coderetreat: Part 8 – Extract and Override

Extract and Override

Blog post series

This blog post is part of a series about legacy coderetreat and legacy code techniques you can apply during your work. Please click to see more sessions about legacy code.

Purpose

Almost always when needing to test existing code we bump against dependencies that make the system untestable. This technique is useful to extract the static dependencies. After that we can use dependency inversion in order to be able to really test the systems.

With this technique we can transform untestable systems into testable systems, step by step. The steps are small because we want to enable safety while changing the code.

Concept

If we have static dependencies, the system is very difficult or impossible to test. If we have slow dependencies the tests we write are very slow and we have slow feedback about the system’s health.

Let’s say we have an ugly production code that calls a static reference.

public class Math {
    public void add(int a, int b){
        int result = a + b;
	System.out.println("The result is " + result);
    }
}

We write a test and run it. The first thing that happens is that we have an exception popping up.

public class MathTests {
    @Test
    public void addWithTwoPositiveNumbersWritesCorrectResultToConsole(){
        Math math = new Math();

        math.add(3,4);

        // how to test???
    }
}

The conclusion is that we cannot really test the system like that, having the static dependency. We do not have a method to take the result of the system, because the result is immediately sent to the console, which is the static dependency. So we need to take measures. Here are the steps for extract and override:

Step 1: Create an empty class that inherits from our production class

public class Math {
    public void add(int a, int b){
        int result = a + b;
        System.out.println("The result is " + result);
    }
}

public class MathForTests extends Math {
}

Step 2: Extract the static reference to another private method. Test the production code still works

public class Math {
    public void add(int a, int b){
        int result = a + b;
        consoleWriteline("The result is " + result);
    }

    private void consoleWriteline(String message){
        System.out.println(message);
    }
}

public class MathForTests extends Math {
}

Step 3: Make the extracted method protected

public class Math {
    public void add(int a, int b){
        int result = a + b;
        consoleWriteline("The result is " + result);
    }

    protected void consoleWriteline(String message){
        System.out.println(message);
    }
}

public class MathForTests extends Math {
}

Step 4: Change the test to use the inherited class and not the production class

public class MathTests {
    @Test
    public void addWithTwoPositiveNumbersWritesCorrectResultToConsole(){
        MathForTests math = new MathForTests();

        math.add(3,4);

        // how to test???
	}
}

Step 5: Override the protected method in the new class that inherits from the production class

public class MathForTests extends Math {
    @Override
    protected void consoleWriteline(String message){}
}

Step 6: Write the minimum code in order to make the method work

public class MathForTests extends Math {
    public String messageWritten;

    @Override
    protected void consoleWriteline(String message){
        messageWritten = message;
    }
}

Step 7: Write the assertion for the test. It is green

public class MathTests {

    @Test
    public void addWithTwoPositiveNumbersWritesCorrectResultToConsole(){
        MathForTests math = new MathForTests();

        math.add(3,4);

        assertEquals("The result is 7", math.messageWritten);
    }
}

Step 8: Test the production code still works

 

By using this technique we can easily avoid any static dependencies.

Outcomes

We will be able to write isolated unit tests for an existing system that has static dependencies.

We started from a code that is highly coupled with a static dependency

public class Math {
    public void add(int a, int b){
        int result = a + b;
        System.out.println("The result is " + result);
    }
}

and we ended with a code where the static dependency is less coupled with the system

public class Math {
    public void add(int a, int b){
        int result = a + b;
        consoleWriteline("The result is " + result);
    }

    protected void consoleWriteline(String message){
        System.out.println(message);
    }
}

But this is not enough. If we want to have a better design we need to extract the consoleWriteline function to a new class and apply dependency inversion.

Extract and override is useful to make the system less coupled and more cohesive.

Remarks

After applying extract and override we might want to continue with refactoring the system more. We might want to use dependency inversion in order to have a system where the static dependencies are abstracted and sent as parameters. We will see more how to do this during the next post.

Even though it might seem like a simple technique, we need to focus on taking baby steps.

This technique is useful to try and understand existing code better. You can see how you can improve the code design in order to have a testable design. The changes we made in the production code were minimal, we just extracted a method. This is an essential aspect: we made minimal changes and the production code still works fine.

History

This technique was first explained in the book Working Effectively with Legacy Code by Michael Feathers.

Code Cast

Please find here a code cast in Java about this session

The post Legacy Coderetreat: Part 8 – Extract and Override appeared first on Adrian Bolboaca.


Viewing latest article 1
Browse Latest Browse All 5

Trending Articles