Software Development

Legacy Code To Testable Code #2: Extract Method

This post is part of the “Legacy Code to Testable Code” series. In the series we’ll talk about making refactoring steps before writing tests for legacy code, and how they make our life easier.

As with renaming, extracting a method helps us understand the code better. If you find it easy to name the method, it makes sense. Otherwise, you just enclosed code that does a lot of things. It can be useful sometimes, although not as extracting small methods that make sense.

Extracting a method also introduces a seam. This method can now be mocked, and can now affect the code as it being tested. One of the tricks when not using power-tools is wrapping a static method with an instance method.

In our Person class, we have the GetZipCode method:

public class Person { 
    String street; 

    public String getZipCode() { 
        Directory directory = Directory.getInstance(); 
        return directory.getZipCodeFromStreet(street); 
    } 
}

The Directory.getInstance() method is static. If we extract it to a getDirectory method (in the Person class) and make this method accessible, we now can mock it.

public class Person { 
    String street; 
    
    public String getZipCode() { 
        Directory directory = getDirectory(); 
        return directory.getZipCodeFromStreet(street); 
    }
    
    protected Directory getDirectory() { 
        return Directory.getInstance(); 
    } 
}

While it’s now very easy to mock the getDirectory method using Mockito, it was also easy to mock the Directory.getInstance if we used PowerMockito. Is there an additional reason to introduce a new method?

If it’s just for the sake of testing – there’s no need to do the extraction. Sometimes, however mocking things with power-tools is not easy. Problems appearing in static constructors may require more handling on the test side. It may be easier to wrap in a separate method.

There are times when extracting helps us regardless of the mocking tool. We can use method extraction to simplify the test, even before we’ve written it. It’s simpler and safer to mock one method, rather than 3 calls.

If our getZipCode method looked like this:

public String getZipCode() { 
    Address address = new Address(); 
    address.setStreet(street); 
    address.setCountry(country); 
    address.setState(state); 
    address.setCity(city); 
    
    Directory directory = Directory.getInstance(address); 
    return directory.GetZipCode(); 
}

Even with power-tools, faking the Address instance and setting the rest of the behavior settings just for retrieving the directory is quite a lot of work, which means a longer test with a long setup. If we extract a getDirectoryFromAddress method:

public String getZipCode() { 
    Directory directory = getDirectoryFromAddress(); 
    return directory.GetZipCode(); 
}

We get more readable code, and we’ll need to mock only one line.

While extracting has its up side, making a method a seam comes with the baggage. If the method is private, and we use power tools to mock it, coupling between test and code is increased. If we make it public, someone can call it. If it’s protected, a derived class can call it. Changes for testability is a change of design, for better or worse.

Reference: Legacy Code To Testable Code #2: Extract Method from our JCG partner Gil Zilberfeld at the Geek Out of Water blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button