ToMethodObject Refactoring

I love refactoring code. To refactor code safely you need automated tests. Some code, especially code not written using Test Driven Development(TDD), make it difficult to write tests for the part of the code you are looking to change.

Usually what you face are a class that has many dependencies, so in your test setup, you have to create all these dependencies to inject into the constructor even though many or perhaps all of these dependencies don't even have anything to do with the part of the code you are looking to change.

Or the method that you want to write a change for is private and the calling public method has a bunch of dependencies which again many will not have anything to do with the part of the code you are looking to change.

You are thinking: "If only this code was in a public method it would be so much easier to test". But you may have heard somewhere that changing the code just to make it easier to test is bad. 

This is a terrible line of thought that has cost me hours of coding. Forget you ever heard such a thing. If this is the first you have heard it, forget that I even said it.


 Testable code is good code, testable design is good design. Don't believe me? Watch this:


Working Effectively With Legacy Code
In the "Fixing Design with Tests" video above, Michael Feathers, the author of Working Effectively With Legacy Code, describes many different code issues that make tests hard to write and the design changes that will improve the design of the code and make tests easier to write.

My new mantra, inspired by Kent Beck's Make the change easy ... make the easy change, is 

Make the test easy to write. Write the easy test.

A common pattern that came up when I started doing this, is a type of "Replace Method with Method Object" refactoring. 

What I would do is pull the code that I want to test into a static method or if it's in a private method then make the method static and then do the "Replace Method with Method Object" refactoring.

Then it was easy to test the new Method Object class.

I ended up doing this so often that I decided to create a Visual Studio Extension ToMethodObject that will take a static method and automatically create the Method Object class for me.

The ToMethodObject extension uses an Agent Noun of the method name to come up with the name of the Method Object class. 

For example, say you wanted to make a change to how a friend is checked for in the TripService class of the TripServiceKata:


Before doing this you would want to have this code covered by automated tests but to do so would result in problems with these 2 calls that are flagged as service calls by the kata:


Instead of trying to mock out the service calls at this time, what we can do is pull out the friend check code here:


 And use the automated extract method refactoring to a static method like this:




Now we can refactor the FriendCheck to a method object using my ToMethodObject automated refactoring:



This creates a new method object class called FriendChecker that is easy to test as it has no tricky dependencies that aren't even needed for the code we want to change.

The original method is automatically updated to call our new FriendChecker method object class:



You can download my ToMethodObject refactoring tool here and you too can start to "Make the test easy to write. Write the easy test!"

Comments

  1. Love this and that's where I would spend 10 to 30% of my daily coding time.
    In my current team they would have forced me to make everything static though and I would have just cried for hours.

    ReplyDelete

Post a Comment

Popular posts from this blog

How to unlock a file in Team Foundation Server(TFS)

Show/Hide formatting text in MS Word 2010