Reputation: 4081
I've got some doubts regarding how to provide defaults for dependencies and how to handle tests for them. Let's say I have class as follows:
class MyService {
private AnotherService dependency;
...
}
As this is legacy application there is no dependency injection (even home grown one). So to provide dependecy there are several ways (e.g. constructor, setter). But I'd like to provide default implementation for this dependency, but I'm in doubt how to do it.
I'd do it by having
class MyService {
private AnotherService dependency = new AnotherServiceImpl();
...
}
but then this dependency is always initialized when MyService is being created. For tests I don't want this, as I want to provide mock impl. I think of something like
class MyService {
private AnotherService dependency;
private AnotherService getDependency() {
if(dependency == null) {
dependency = new AnotherService();
}
return dependency
}
setDependency(AnotherService dependency) {
this.dependency = dependency;
}
}
Now, if all depedency calls are done via getDependency() first, dependency is loaded the lazy way I think and I can set my own for test.
I know it is hard to start introducing changes like dependency injection in legacy code which doesn't have it already. E.g. if I provide my dependency in constructor, the problem with dependency instantiation just shifts one level up.
Second question is how to provide dependencies if there is only one implementation right now. I'm using Mockito and its @InjectMocks can inject mock into private field. I wonder if there is a need to expose setDependency or constructor arg dependency and make this one impl with interface? Isn't it overengineering it right now? I don't want to alter my code for tests only.
Upvotes: 0
Views: 359
Reputation: 39248
Another option is to create virtual methods than can be overridden by your tests
Example: http://www.unit-testing.net/CurrentArticle/How-To-Remove-Data-Dependencies-In-Unit-Tests.html
Upvotes: 0
Reputation: 1453
You could use an Abstract Factory for your dependencies.
class MyService {
private AnotherService dependency;
private static ServiceFactory serviceFactory = ServiceFactory.getInstance();
...
public void action() {
...
AnotherService dependency = serviceFactory.getAnotherService();
...
}
}
And Unit Testing should be easier. Just return the mock implementation in your test case from the ServiceFactory class.
Before DI frameworks became popular - Abstract Factory pattern was used everywhere.
Upvotes: 0
Reputation: 403451
A common patterm is to overload your constructors:
class MyService {
private AnotherService dependency;
MyService() {
this(new AnotherServiceImpl());
}
MyService(AnotherService dependency) {
this.dependency = dependency;
}
...
}
Existing code will work as before, by calling the default constructor, whereas tests can use the constructor with the injectable dependency.
Upvotes: 1