Dependency Injection and Unit Testing
Dependency Injection and Unit Testing
In recent years, Dependency Injection may have buzzed into your ears quite often. You may already know
that it has nothing to do with drug addiction, but with some cool object-oriented concept. You may also have
heard of the Spring Framework, a so-called Dependency Injection container. You might be under the
impression that Dependency Injection equals Spring. But no, Dependency Injection is a simple concept which
can be used anywhere, without any Dependency Injection container, and especially useful in unit testing. In
this article, we will see
A simple car
Let's consider a simple example, using engines and cars. We'll leave classes and interfaces empty for clarity.
A car has an engine, and we'd like that car to be equipped with JavaRanch's famous MooseEngine™.
This is a great car, but it cannot have any other kind of engine, although there are other brands available on
the market. We say that the Car class is tightly coupled to the MooseEngine class. There's nothing wrong
with it, the MooseEngine™ is great, but what happens if we finally decide to equip it with another engine ?
1 de 5 2015-09-07 18:26
Dependency Injection and Unit Testing http://www.javaranch.com/journal/200709/dependency-injection-unit-tes...
Programming with interfaces is an important concept in Dependency Injection. I can already hear you
screaming, "wait a minute! That's an interface you're using here, where is the concrete class? Where do you
set it? I want my MooseEngine™ in my car". We could set it the following way:
But would that be useful ? It doesn't look much different from the first example. Our car is still tightly
coupled to our beloved MooseEngine™. So? Where do we set (or inject) our car's engine ?
One way to set dependencies is to pass the concrete implementation of the depending class to the constructor.
Our Car class would become:
We could then create a Car using any kind of engine. For example, one car using the great MooseEngine™
and another one using the crappy SlowEngine:
2 de 5 2015-09-07 18:26
Dependency Injection and Unit Testing http://www.javaranch.com/journal/200709/dependency-injection-unit-tes...
Another common way to set dependencies is to use setter methods. Using setter methods is recommended
instead of the constructor when many dependencies need to be injected. Our car class would then be written
that way:
It looks very similar to the constructor based injection, doesn't it? We would then implement the same cars
we have used above the following way:
You have already noticed that FarmServlet is tightly coupled to the FarmEJBRemote instance, which was
retrieved via a call to "FarmEJBUtil.getHome().create()". It makes it very hard to test. When unit testing, we
3 de 5 2015-09-07 18:26
Dependency Injection and Unit Testing http://www.javaranch.com/journal/200709/dependency-injection-unit-tes...
don't want to use any database. We don't want to access an EJB server either. That would make unit tests both
difficult to execute and slow. So in order to unit test the FarmServlet class smoothly, we'd better make it
loosely coupled. To remove the tight dependency between FarmServlet and FarmEJBRemote, we could use a
setter based injection:
In the real deployment package, we will make sure that an instance of FarmServlet's remote member will be
properly injected via "FarmEJBUtil.getHome().create()". In our unit test, we will use a dummy mock class to
act like a FarmEJBRemote. In other words, we will make a mock class implementing FarmEJBRemote:
4 de 5 2015-09-07 18:26
Dependency Injection and Unit Testing http://www.javaranch.com/journal/200709/dependency-injection-unit-tes...
servlet.doAction( mockServletData );
assertEquals( 1 , mockRemote.getNbCalls() );
assertEquals( "dog" , mockRemote.getSpecies() );
assertEquals( 27 , mockRemote.getBuildingID() );
}
}
5 de 5 2015-09-07 18:26