Unit testing without dependency injection - java

Code from Spring in Action :
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
public class BraveKnightTest {
#Test
public void knightShouldEmbarkOnQuest() {
Quest mockQuest = mock(Quest.class);
BraveKnight knight = new BraveKnight(mockQuest);
knight.embarkOnQuest();
verify(mockQuest, times(1)).embark();
}
}
I understand the use of dependency injection, which allows us to switch implementation without modifying the depending code.
The book says "terribly difficult to write a unit test ...".
However, I am not able to understand how it will be very difficult for unit-testing without dependency injection! My intuition refuses to co-operate !
Can you start writing junit/unit testing for the class "DamselRescuingKnight" and for any other better example class (without DI), to make me realize the point/stage at which DI makes unit testing easier ?

The difficulty in your above example comes when you try to test DamselRescuingKnight. Assume, you want to test that one (see below)
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}
public class DamselRescuingKnightTest {
#Test
public void knightShouldEmbarkOnQuest() {
DamselRescuingKnight knight = new DamselRescuingKnight ();
knight.embarkOnQuest();
// now what?
}
}
how can you be sure that knight.embarkOnQuest() does actually do anything? The answer is that you can't because you can't access the quest instance it uses internally.
Now in order to be able to test such a class, you would add a getQuest() method to the Knight, and then also add a isEmbarked() method to Quest.
It is also quite fair to say, that this example is very simple, because the knight only calls the quest without parameters, and nothing else. If knight would interact with a quest and also get some weaponary from a Blacksmith, then you would also somehow need to allow access for that. You could probably do all the boilerplate to get that done. But then assume, you're passing parameters to blacksmith - how do you ensure that the passed parameters were correct? Or how do you ensure that the knight gets his/her weapon before going to the quest?
This is where dependency injection comes to the rescue. you can just create mocks (either by using a mock framework, or by implementing your own mocks) so that you can verify that your knight does the expected things.

The problem is of course the quest variable. You want to somehow check that the embark() method is invoked. Without being able to replace it with a mocked instance, this is very hard.
If the variable were protected instead of private, the test case could overwrite it by virtue of living in the same package.
You can also use Aspect-Oriented Programming to replace the variable.
But the easiest is if the code is written with dependency injection from the get-go.
You ask to see how AOP can be used. The following is an example of an AspectJ pointcut that you can use in a unit test to replace the RescueDamselQuest instance with a mocked one called MockRescueDamselQuest (apologies if I don't get the syntax exactly right, it has been a while since I used AspectJ):
aspect MockRescueDamselQuestInstantiations {
RescueDamselQuest around (): call(RescueDamselQuest.new()) {
return new MockRescueDamselQuest();
}
}
This will catch any instantiations of RescueDamselQuest (i.e. calls to new RescueDamselQuest()) and return a MockRescueDamselQuest object instead.
Given how much more wiring this requirest, I'd strongly suggest using dependency injection instead!

This perplexed me as well when I was reading this in Spring in Action. After reading above answers I wanted to add that when DI is not used then Junit method need to call method of object which is private (which is in accessible) and this object Quest is created in constructor of DamselRescuingKnight so test case for embarkQuest() can't be written. On contrary when using DI then you are externalizing object creation and Junit method can create that object so it will be accessible to it then can test emabarkQuest() which eventually need to test quest method

Related

How to mock an object created via Class.newInstance(className)?

I'm trying to add unit tests to some legacy code that has a String class name passed to it and that creates an object implementing a particular handler interface using Class.newInstance(String className). I can control the class name I'm passing, I can get a pointer to the new handler object (via a getHandler() call), and I would like to observe calls to it using Mockito.
My current solution is:
Create a new test class TestHandler that implements the interface.
Have that test class contain a Mockito mock object that also implements the interface.
Manually pass through all the interface methods to the mock object.
Make the mock object accessible via a getMock() method.
Observe the object by making verify() calls to objectUnderTest.getHandler().getMock().
This works, but feels a little inelegant, especially having to manually write all the pass-thru methods.
Is there a better solution?
Fundamentally, you're running into the same problems as trying to test a newly-created instance using new; the Class.newInstance (probably properly Class.forName(foo).newInstance()) doesn't hurt you, but doesn't help you either.
As a side note, your TestHandler sounds like a general purpose delegate implementation, which sounds pretty useful anyway (particularly if you ever need to write a Handler wrapper). If it is, you might want to promote it to be adjacent to your Handler in your production code tree.
Though I recognize that you mention legacy code, this becomes very easy if you are allowed to refactor to include a testing seam. (Ignoring reflective exceptions here for ease of explanation.)
public ReturnType yourMethodUnderTest(String className) {
return yourMethodUnderTest(Class.newInstance(className));
}
/** Package private for testing. */
public ReturnType yourMethodUnderTest(Handler handler) {
return yourMethodUnderTest(Class.newInstance(className));
}
You could also extract the object creation and replace it in your test:
/** Instance field, package-private to replace in tests. */
Function<String, Handler> instanceCreator =
( x -> (Handler) Class.forName(x).newInstance());
public ReturnType yourMethodUnderTest(String className) {
Handler handler = instanceCreator.apply(className);
// ...
}
You could even just extract it to a method and replace it in your test:
public ReturnType yourMethodUnderTest(String className) {
Handler handler = createHandler(className);
// ...
}
/** Package private for testing. */
Handler createHandler(String className) {
return Class.forName(className).newInstance();
}
#Test public void yourTest() {
// Manually replace createHandler. You could also use a Mockito spy here.
ObjectUnderTest objectUnderTest = new ObjectUnderTest() {
#Override Handler createHandler(String className) {
return mock(Handler.class);
}
}
// ...
}
Side note: Even though Mockito creates a named dynamic type, you almost certainly will not be able to hack it in and allow your code to create it by name. This is because the call to mock registers the instance within Mockito's internal state.
// BAD: Unlikely to work
#Test public void yourTest() {
objectUnderTest.methodUnderTest(
mock(Handler.class).getClass().getName());
// ...
}
Create a public method where you will place the logic to fetch the newInstance of the class
ClassA objectClassA=createNewInstance(className);
likewise,and
public ClassA createInstance(String className){
return (ClassA) (Class.forName(className)).newInstance();
}
Now suppose we were creating an instance of classA inside of ClassB
then in TestClass of B, we can simply mock this createInstance method
doReturn(mockClassA).when(mockClassB).createInstance(className);

How to make JUnit test fall down if constuctor is present?

I am learning JUnit and Test Driven Development practice. I have empty Money interface:
public interface Money {
}
CommonMoney class which implements Money interface:
public class CommonMoney implements Money {
private CommonMoney() {
}
public static Money create(String decimalPart, Currency currency) {
return new Money() {
};
}
}
And MoneyTest class which tests CommonMoney
public class MoneyTest {
// some test cases before
#Test
public void shouldNotCreateCommonMoneyObjectWithEmptyConstructor() {
#SuppressWarnings("unused")
Money money = new CommonMoney();
fail();
}
}
For now test case shouldNotCreateCommonMoneyObjectWithEmptyConstructor is red, but it should be green if constructor of CommonMoney is private and red if it is public. Is it possible to make test case like this? And how can I do it?
Is it possible to make test case like this?
Yes, it is possible to implement this test by using java reflection, for example see this question. Otherwise, you cannot test, that the private constructor is present, from outside of that class - the code just won't compile.
However, it doesn't really make sense to test this. Access modifiers are really there for developer convenience and to limit the access scope. Arguably, scope limitation is also done for convenience.
Your tests should cover public API and not look at private implementation.
This is not the sort of thing you need to test.
As Agad pointed out, the code won't compile the way it is anyway, because by making the constructor private you've made it impossible to create the object with an empty constructor.
The compiler is effectively doing the check for you, so you don't need to write a specific test to check for it.

Replacing a java method invocation from a field with a method call

I am trying to build a mocking framework in java which fits to a specific requirement of a project.
The scenario is, I have a method
public String returnRandom(){
String randomString = this.randomGenerator.returnRandom()
}
The randomGenerator is a dependency of this class and is injected to the object only in runtime. Means it would be null if the object is created without the dependency injection framework.
During an isolation test, I want the replace assignment to the statement
this.randomGenerator.returnRandom();
with a method which returns a stray random value, say "Helloworld".
I was trying to use javassist.expr.FieldAccess for the same, using which I can replace the field to a no operation and method call can be modified using javassist.expr.MethodCall.
I am not able to figure out how to replace the field with a dummy or a no operation. Is this possible using java assist or should I go for a more low level bytecode manipulation like asm?
Note:
I could achieve replacing of a method call which doesn't originate on a field using javassist.expr.MethodCall. For example if the above example is
public String returnRandom(){
String randomString = returnRandom();
}
I am able to replace as
public String returnRandom(){
String randomString = MockedString.getSampleRandom();
}
The best thing you can do is to create an interface for the random generator, say:
public interface RandomGenerator {
public String returnRandom();
}
Then your original random generator can implement this interface, and the class that uses a random generator can depend on a class with a RandomGenerator interface.
Once you have this, it is fairly straight-forward to test. You create a mock generator that does what you want:
public class MockRndGenerator implements RandomGenerator {
public String returnRandom() {
return "Helloworld";
}
}
and when you're testing, you inject this class instead of the original.
public class Demo {
public Demo (RandomGenerator rndGenerator) {
this.randomGenerator = rndGenerator;
}
public String returnRandom(){
String randomString = this.randomGenerator.returnRandom()
}
}
* UPDATE *
Since I can't add code in comments, here is the Mockito solution:
you can always use Mockito to avoid creating physical mocks, and then you can set up expectations and inspections on the way
class Test {
public static rndTest() {
RandomGenerator rnd = Mockito.mock(RandomGenerator.class);
Mockito.when(rnd.returnRandom()).thenReturn("Helloworld");
Demo = new Demo(rnd);
}
}
I could solve the problem using javassist.expr.MethodCall. Below is the expression editor class used for checking the feasibility.
This replaces the targetMethod call (methodcalltoReplace) with the code used to get a mock object.
new ExprEditor() {
#Override
public void edit(MethodCall m) throws CannotCompileException {
try {
if (m.where().getName().equals(sourceMethod)) {
if (m.getMethod().getName().equals(methodcalltoReplace)) {
if(lineNumberOfMethodcalltoReplace == m.getLineNumber()){
// The content of the hardcoded string can be replaced with runtime data
m.replace("$_ = ($r)"+"new com.nuwaza.aqua.sample.SampleForMethodInvocationFieldAccess().helloworld();");
}
}
}
} catch (NotFoundException e) {
e.printStackTrace();
}
super.edit(m);
}
For a detail documentation see,
Javaassist tutorial, introspection and customization
One approach I have done in the past is to create a back door static method to replace your random generator with a mocked version. You can then use mockito to instruct what it should return. By making it static you avoid having to create many of them, just one for the whole class. Like anything else it has pros and cons but it might fit your specific need.
Instead of called the field directly, like you are in your example, you could use a method instead getRandGen(). That method would either use the local random generator or the mocked static one if it is set.
Essentially this is a back door to overwrite your dependency framework's chosen object with one you select yourself at runtime during unit testing and it is static so it affects the whole class and not only specific instantiations.

Guice runtime dependency parameters reinjection

A question about Guice. I'm still learning it, but I can understand the fundamentals.
This question was already asked a couple of times on the net, but never with a concrete answer(none that I could find).
Say I have a situation like on the picture(a similar example was somewere on the net).
public class Dog {}
public class Walk implements Walkable {
private final Dog dog;
private final boolean leash;
#Inject
public Walk(Dog dog, #Assisted boolean leash) {
this.dog = dog;
this.leash = leash;
}
public void go() {
}
}
public interface Walkable {
void go();
}
public interface WalkFactory {
Walk create(boolean leash);
}
public class AssistedMain {
public static void main(String[] args) {
Injector i = Guice.createInjector(new AbstractModule() {
protected void configure() {
install(new FactoryModuleBuilder().
implement(Walkable.class, Walk.class).
build(WalkFactory.class));
}
});
Walk walk = i.getInstance(WalkFactory.class).create(true);
}
}
That's all great. But the question is - can I, somehow, reinject that object instance to the "container"(injector) to be used on the classes that rely on this dependency.
So, lets add a interface Person, class PersonImpl.
The new classes source are:
public interface Person {
void walkDog();
}
public class PersonImpl implements Person {
private Walkable walkable;
#Inject
public PersonImpl(Walkable walkable) {
this.walkable = walkable;
}
public void setWalkable(Walkable walkable) {
this.walkable = walkable;
}
public void walkDog() {
walkable.go();
}
}
So, the question is - am I, somehow able to actually inject this particular instance into the added object. This is a simple example, but we can presume there are 10 levels of classes below this one.
The solution I found is not very flexible. Something like:
Injector i = Guice.createInjector(new SimpleModule(false, dog));
And then bind to concrete instance. That's not very dynamic. Basically, every time I need a different runtime/dynamic parameter I have to recreate the injector.
The Provider<T> is nice, the FactoryModuleBuilder helps, but how can I inject the objects back?
Are there more dynamic solutions to this problem?
Thanks.
MPierce - agreed. Ill try to explain the way i visualized the problem(you can correct me if im wrong).
Being originaly derived from a "service locator" pattern, the idea that it can manage more than services is optimistic to say the least.
We could split the application into Service and Data classes, or you could say that we have application and infrastructure code - "Dependency Injection", a great book.
So, basicly, dependecy injection, and dependency injection frameworks in general are great. For solving infrastructure, or "service" code.
Any dynamic(runtime) parameters being injected into the Container/Injector are basicly forcing you to end the object graph.
For example, we have the folowing design:
EmailMessage is a runtime parameter. It can be "injected" into email service outside the Container/Injector, but it ends the object graph. If we want to request EmailDispatcher, after we injected the EmailMessage into EmailService(which is, I repeat, done outside injector), we could no longer fetch EmailDispatcher from the injector.
Then, you could redesign your model so it "fits" into the Container/Injector concept of dynamic parameters.
But then again, you forced the design, and suddenly, EmailDispatcher has too many responsibilites. It could be used in such a context, where you dont have many infrastructure classes.
And when you have a design like you have in the third example picture, you cannot use the Injector/Container to fetch you a NextService3 instance(nor any below the level of EmailDispatcher).
The problem being - if you have any dynamic(runtime) parameters, you can only use dependency injection for classes above the class that requires a dynamic parameter, you can forget the classes below.
Phew.
Correct?
Part of the problem depends on how you're resolving that 'false' is the thing you want to set for the leash field. Is that coming from config data or what?
A provider method may be helpful...
class FooModule extends AbstractModule {
...
#Provides
Walkable getWalkable(Dog dog) {
boolean leash = getBooleanFromSomewhere();
return new Walk(dog, leash);
}
}
If you can clarify where that boolean is coming from, it'll help me to understand what type of approach is applicable.
You can use custom scopes, much like when using guice servlets. That way you can create your instance, and then seed it in the injector.

How to write unit test using mock object?

The more I read mock example, the more I get confused...
I have classA method eat() that calls FatDude class eatThemAll()
public class classA {
FatDude dude = new FatDude();
public String eat() {
String result = dude.eatThemAll();
}
}
public class FatDude {
public String eatThemAll() {
return "never full";
}
}
Now I want to test classA eat() method by mocking FatDude class.
public class MockFatDude extends FatDude {
//override
public String eatThemAll() {
return "very full";
}
}
------------- test --------------
public class DoTest {
public void runTest() {
classA cl = new ClassA();
String out = cl.eat();
assertEqual(out, "very full");
}
}
This DoTest runTest() won't use MockFatDude class of course. One way I can think is to change the code to pass FatDude to eat() method of ClassA like:
public class classA {
public String eat(FatDude dude) {
String result = dude.eatThemAll();
}
}
Then change my test method to:
public class DoTest {
public void runTest() {
classA cl = new ClassA();
String out = cl.eat(new MockFatDude());
assertEqual(out, "very full");
}
}
But as you can see, I had to change the source code to meet my need.
Is this the right way to do? What if I am not allowed to change my source code?
I know if I apply TDD concept, it is OK to change source code but I would like to hear
some opinion or advice if what I have shown above is right way to do.
Mocking and the Dependency Inversion Principle (DIP) go hand in hand, and in most languages, Mocks work best by decoupling classes by means of interfaces.
In your instance, this will work without you needing to change code: (Edit : I mean, in future, if you design your app this way, you won't need to change code to mock dependencies :))
Abstract an interface IDude
Concrete classes FatDude (and MockFatDude) should implement IDude interface
provide a mechanism for an IDude instance to be 'set' or injected into classA - Dependency Injection (constructor or get / sets); or Service Locator pattern work best (to replace a concrete classfactory)
Also note that many mocking frameworks actually allow you to build up the Mock concrete class 'on the fly' (see MoQ et al), so you can create the functionality of MockFatDude directly in your unit test.
Yes. You've stumbled on some good design directly because of your unit test. If you look more closely, you'll see that you removed the coupling between classA and FatDude. Now FatDude can be an interface for behavior that gets passed in when needed. ClassA doesn't need to know what kind of FatDude it's getting, or how to construct a FatDude (with cheeseburgers?).
Your solution is exactly what I would have done. There's nothing wrong with changing your code to accomodate TDD, as long as you understand the reasons and the benfits/drawbacks to making such changes.

Categories