Hi guys, it’s been a while that I haven’t posted anything. I was thinking writing all those technical things sometimes is not enough for the reader to visualize the concept. So I came up with a screencast this time. I’ll try to create these screencasts once a week and will cover different topics. This series will contain Making Code More Testable talks only. For other topics, I’ll create different series. Anyways, let’s get back to the overview :)
In this first screencast I’ll try to cover how you guys could break the static dependencies in your constructor. Let me give you some brief overview about these dependencies:
Dependencies
Dependencies are everywhere in our little world. Every unit, every module is depending on something. Sometimes it’s another unit, sometimes it’s another modules, and sometimes it’s another library. And there are lots of discussions currently going on to make your units, modules more scalable and more isolated! All OSGi, maven, DI (Dependency Injection) and SOLID principles are just for this purpose. To help you to break/isolate/modulate your code base.
In this screencast I’m gonna talk about only a single part of whole this picture. Static dependencies within your constructors.
Static Dependencies Within Constructors
This type of dependencies are very evil when it comes to do unit testing. It could turn into a very big puzzle game sometimes. The basic idea is some developers tend to place their dependent services or non-value objects into the constructor and using singleton and/or static methods. Without being aware of what they’re doing, they sometimes even place if/else, try/catch, switch/default statements into this tiny part of the code.
So how it happens? Very easy, let’s consider the following code snippets:
/** My class. */
public class MyClass {
private Service service;
/** Default constructor */
public MyClass() {
// lots of logic that shouldn't be here..
// and
this.service = Service.getInstance();
TimeService.recordTime();
}
}
(EDIT) As you may clearly see, it’s very hard to test this unit since it has non-injectable static dependencies. So what do we need to do?
There are couple ways to break these dependencies. Before going into too deep, I want to clarify something here. “DON’T EVER DO THIS”! When you write your code, maybe you don’t follow TDD or anything. But please consider there will be some people that have to deal with this code after you. Then again, if you’re selfish.. There is no more word to say!
Breaking the Dependencies
As I said, there are couple ways to break these sort of dependencies.
Constructor Delegation
First and my favourite is Constructor Delegation. The basic idea for this technique is create another constructor which takes these dependencies for dependency injection and delegate the first constructor to the second one. Please consider following code’s before/after and usage scenarios:
// BEFORE 'constructor delegation'
public class LibraryManager {
private LibraryService service;
public LibraryManager() {
this.service = LibraryService.getInstance();
}
// more code
}
// AFTER 'constructor delegation'
public class LibraryManager {
private LibraryService service;
public LibraryManager() {
// delegate to the new constructor
this(LibraryService.getInstance());
}
// new constructor
public LibraryManager(LibraryService service) {
this.service = service;
}
// more code
}
// USAGE 'in the test'
LibraryManager manager = new LibraryManager(mockLibraryService);
// ...
// do your assertions
Endo Testing
Second technique is from Endo Testing. The technique here is extracting these dependencies to getter equivalents and overriding these methods for returning the mock/stub/fake ones. One thing here is your getter methods should be package private or protected. Please look at the following before/after and usage scenarios again:
// BEFORE 'endo testing'
public class SmartHitter {
private Exchange exchange;
public SmartHitter() {
this.exchange = Exchange.getActiveExchange();
}
// more code
}
// AFTER 'endo testing'
public class SmartHitter {
private Exchange exchange;
public SmartHitter() {
this.exchange = getActiveExchange();
}
protected Exchange getActiveExchange() {
return Exchange.getActiveExchange();
}
// more code
}
// USAGE 'in the test'
final Exchange mockExchange = mock(Exchange.class);
SmartHitter hitter = new SmartHitter() {
@Override
protected Exchange getActiveExchange() {
return mockExchange;
}
};
// ...
// do your assertions
Setter Injection
The last one is not applicable to all scenarios, but it’s another dependency injection mechanism (@see Dependency Injection). For this one, you basically create a setter method for your dependency and allow test to inject this dependency. Let’s look at the example:
// BEFORE 'setter injection'
public class AjaxPriceModifier {
private CatalogService catalogService;
public AjaxPriceModifier() {
// initialization..
this.catalogService = CatalogService(sessionHelper.getStore());
}
// more code
}
// AFTER 'setter injection'
public class AjaxPriceModifier {
private CatalogService catalogService;
public AjaxPriceModifier() {
// initialization..
this.catalogService = CatalogService(sessionHelper.getStore());
}
public void setCatalogService(CatalogService catalogService) {
this.catalogService = catalogService;
}
// more code
}
// USAGE 'in the test'
AjaxPriceModifier modifier = new AjaxPriceModifier();
modifier.setCatalogService(mockCatalogService);
// ...
// do your assertions
As you may notice, without a getter of that dependency your code still has the dependencies. It’s very wise to place a getter for that dependency and use that getter (as in Endo Testing) method in the constructor.
Summary
My personal favourite is Constructor Injection since it’s more intuitive when you’re coding the test. It clearly describes what dependencies you need to test that unit. Okay, now you can watch the screencast. Hope it turns some lights on :) All comments are welcome!
