E4 DI in unittests? [message #900647] |
Tue, 07 August 2012 19:20  |
Eclipse User |
|
|
|
Hi to anyone,
I want to write unittests regarding classes that are injected in my real app.
I want to inject these objects in my unittests too.
Is there a API for injecting objects and all their fields recursively?
What's the best way to test this enviroment?
Do you have an example to provide?
Thanks in advance
Best regards
Markus
|
|
|
|
Re: E4 DI in unittests? [message #900680 is a reply to message #900651] |
Wed, 08 August 2012 03:21   |
Eclipse User |
|
|
|
Hi again,
my problem is the following:
I use DI to inject my own objects.
For example:
@Creatable
class A {
@Inject private B someField;
@Inject private C someOtherField;
}
@Creatable
class B {
@Inject C thirdField;
}
So from scratch, A.B.C is null, and I can't set it from outside.
OK, I could use mocking, but I cannot mock a private field with Mockito, I guess, so I have to make it at least package private.
Better would be to get these things injected, I think. This would simplify the test itself.
Could you give me a hint, what's best practice in this context?
Thanks a lot.
Best regards
Markus
|
|
|
|
|
Re: E4 DI in unittests? [message #900788 is a reply to message #900680] |
Wed, 08 August 2012 09:35   |
Eclipse User |
|
|
|
To build off of your example here:
Markus Oley wrote on Wed, 08 August 2012 02:21
@Creatable
class A {
@Inject private B someField;
@Inject private C someOtherField;
}
@Creatable
class B {
@Inject C thirdField;
}
Just be very careful that there isn't a circular dependency such as:
@Creatable
class C {
@Inject /*qualifier*/ A fourthField;
}
From a java standpoint this certainly does not create any issues. The problem is if there aren't any usable instance of A / B / C in the context, injection will fail. (I don't know if there will be any listed error/warning)
If you need/want the fields to be private for some reason, you can use the same approach the DI engine uses with reflection for the mock objects. (See the code below or the attached file. But in general I agree with Tom, (whether using DI or not) if I need to test a field in a unit test, I make it package-private.
Also, the code below is only a sample and isn't quite 'ready to go'. A couple of things still need to be implemented, but it will at least get you started.
JD
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class MockInjector {
public Object getInstance(Class<?> testClass) {
Object instance = null;
try {
instance = testClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (instance == null) {
Constructor<?>[] constructs = testClass.getDeclaredConstructors();
// choose a constructor
Class<?>[] params = constructs[0].getParameterTypes();
Object[] paramInstances = new Object[params.length];
// need to create logic to provide parameters for desired constructor
try {
instance = constructs[0].newInstance(paramInstances);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return instance;
}
public void mockInject(Object testClassInstance, String fieldName, Object fieldValue) {
Class<?> clazz = testClassInstance.getClass();
Field testField = null;
try {
testField = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
/*
* It doesn't matter if the field is private or public, by
* invoking setAccessible(true) it removes the accessibility
* checks performed by the JVM by setting a flag. It does not
* remove the security checks. Effectively this eliminates
* encapsulation.
*/
testField.setAccessible(true);
try {
testField.set(testClassInstance, fieldValue);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.04856 seconds