Why Powermock PrepareForTest prevent mock inject? - powermock

My code is like below:
public class RealWorldBoImpl extends AbstractBoImpl<T> implements SomeBo{}
And
#RunWith(PowerMockRunner.class)
#PrepareForTest({RealWorldBoImpl.class})
public class RealWorldBoImplTest {
#InjectMocks
private RealWorldBoImpl realWorldBo;
#Mock
private RealWorldDAO realWorldDAO;
#Test
public void changeStatusMainSubString() throws Exception {
long id = 1L;
}
In this case, realWorldDAO cannot inject to realWorldBo. But when I delete PrepareForTest, it works.
I also tried other classes, they worked well. It seems RealWorldBoImpl is special that when prepare for it, it will not inject mocks correctly.
I debugged this code, and found that, in org.mockito.internal.util.reflection.FieldInitializer#checkParameterized, constructor.getParameterTypes() is not empty and has a constructor with the class IndicateReloadClass.
private void checkParameterized(Constructor<?> constructor, Field field) {
if(constructor.getParameterTypes().length == 0) {
throw new MockitoException("the field " + field.getName() + " of type " + field.getType() + " has no parameterized constructor");
}
}
But I don't know what's special with RealWorldBoImpl. It just extends a parent class and implements an interface. Does it matter?

When PowerMock prepares a class which has a superclass other than Object it adds a constructor to the class which takes an argument of type org.powermock.core.IndicateReloadClass.
Why PowerMock does this? PowerMock implements superclass constructor suppression through this mechanism.
In your case because RealWorldBoImpl derives from AbstractBoImpl PowerMock adds the following constructors to RealWorldBoImpl, AbstractBoImpl classes:
public RealWorldBoImpl(IndicateReloadClass var1) {
super(var1);
}
public AbstractBoImpl(IndicateReloadClass var1) {
super(); //assuming the parent class is Object otherwise super(var1)
}
and changes the default no-arg constructor of RealWorldBoImpl to the following:
public RealWorldBoImpl() {
Object var1 = MockGateway.constructorCall(Desc.getClazz("org.example.RealWorldBoImpl"),
new Object[0], Desc.getParams("()V"));
if (var1 != MockGateway.PROCEED) {
super((IndicateReloadClass)null);
} else {
super();
}
}
That was the PowerMock part now let's get to the Mockito part.
Mockito has two injection strategies (MockInjectionStrategy): ConstructorInjection and PropertyAndSetterInjection.
ConstructorInjection uses constructor to inject mocks and is used if the injectee has at least one non-default constructor (a constructor that takes at least an argument). In case the injectee has only a no-arg constructor, Mockito uses PropertyAndSetterInjection which uses setter method and if there is no setter method it injects the mocks directly by setting the field's value through reflection.
In your case when you prepare RealWorldBoImpl class you have a constructor with one argument and Mockito uses ConstructorInjection to inject mocks to your object through the constructor that was added by PowerMock (and as there's no mock of type IndicateReloadClass, Mockito passes null to the constructor but that does not matter as the constructor does nothing) and as a result no mocks are injected.
So how can you solve the problem? If you have more than one mock to inject, then add a constructor to the injectee class with as many arguments as the number of mocks you want to inject. As long as you have a constructor with more than one argument, injection will work otherwise your injectee class should have Object as it superclass.
If you have only one mock to inject, you can add a dummy argument to the constructor to make Mockito choose your constructor over the one added by PowerMock:
public RealWorldBoImpl(RealWorldDAO realWorldDAO, String dummy) {
this.realWorldDAO = realWorldDAO;
}

Related

Does Mockito support #Any #Inject Instance<> interface?

I have a init() method that use injected private instance<>. How can I test this class using JUnit or Mockito? I tried to make some fake class and add them to a list and set this list to my private field but I have this error
java.lang.IllegalArgumentException: Can not set javax.enterprise.inject.Instance field ......
MyClass is:
#Singleton
#Startup
public class HandlerManager {
#Any
#Inject
private Instance<RollbackHandler<RollbackData>> handlers;
private RollbackHandler<RollbackData> rollbackHandler;
#PostConstruct
public void init() {
for (RollbackHandler<RollbackData> bean : handlers) {
//do something
}
}
}
Any annotation is not processed by frameworks, unless you use custom work. you will have to define all those dependencies as mocks in your test using #Mock and call injectMocks() from before test methods such as setup(). It is a multi part problem.
Use constructor injection, field injection is evil. you still will be able to annotate your constructor with #Inject.
when(provider.iterator()).thenReturn(list.iterator);
works for me.
You can create a temporary list with concrete implementations of the RollbackHandler, and mock the iterator() method of your Instance<RollbackHandler<RollbackData>> object so that it returns the iterator of the temporary list.
Example:
private void mockIterator() {
Instance<RollbackHandler<RollbackData>> handlers = mock(Instance.class);
List<RollbackHandler<RollbackData>> handlersList = Collections.singletonList(new RollbackHandlerImpl<>());
when(handlers.iterator()).thenReturn(handlersList.iterator());
}

Testing constructor when using #Before annotation

I want to test SomeClass methods.
For that, I need SomeClass instance in every test so I'm using #Before annotation and initiate an instance of SomeClass named SC.
The problem is:- How can I test the constructor function after I already use it? It doesn't make sense.
Additional question:- The constructor can get number of arguments and they can influnce the methods outputs, should I mock this class instead of creating an instance of it?
public class SomeClassTest {
SomeClass SC;
#Before
public void initlize() throws IOException{
SC= new SomeClass (argument1,argument2,..);
}
#Test
public void ConstructorTest() {
}
Just don't use the object SC in your ConstructorTest. If you wan't to test a certain outcome from the construction of a SomeClass object with certain parameters then just construct it as such within your ConstructorTest and then assert the relevant outcomes you expect on the newly constructed object.
And no you shouldn't be mocking this class. The test is for testing this class so if you mock it's behaviour then you aren't really testing anything.

Load a mocked class in Mockito

Is there an easy way, using Mockito, to load a mock class when another is requested OR to override the test ClassLoader?
Basically I have a class Foo that has a member "ClassA" in it. I want to replace to use "TestClassA" instead of "ClassA" during testing. I don't want to use dependency injection because it doesn't make any sense for actual operation. (It can never be anything other than ClassA)
Can I do this?
It can never be anything other than ClassA
...except that it is, in your test. Test code is real code, and though that doesn't mean it should sneak into your production application, it does mean that you need to write in the flexibility you need for all of its use cases, and that includes testing.
Mockito works via subclasses: A mockFoo created by mock(Foo.class) or #Mock Foo mockFoo is actually a proxy subclass Mockito created that overrides each of Foo's methods. As you can tell from that description, Mockito thus cannot change the behavior of every Foo object and especially cannot change the type of the object returned from new Foo().
You have two options, that I can see:
Accept a ClassA or InterfaceA instance in one of your constructors. If you put your tests in the same Java package as your class under test (even in a different source tree), you can even make the constructor package-private, or keep it private and create a static factory method like createForTest(ClassA).
Example:
public class ConsumerToTest {
private final ClassA classA;
/** For public use. */
public ConsumerToTest() {
this(new ClassA());
}
/** For use in tests. */
ConsumerToTest(ClassA class) {
this.classA = classA;
}
// ...
}
Use PowerMock, which has a Mockito integration known as PowerMockito. Though Mockito uses pure proxy subclasses and code generation, PowerMockito actually rewrites the bytecode of the system-under-test. This means that you can mock static methods and constructors that Mockito couldn't adjust on its own through polymorphism.
Personally, I very much prefer solution 1: The code is yours to control, and as long as you're clear that your test is a first-class consumer of your system-under-test, you're free to design it to be testable in the first place.
Doing it by constructor is what I prefer.
For example
public class Foo {
private ClassA classA;
public Foo(ClassA classA) {
this.classA = classA;
}
}
public class FooTest {
private Foo foo;
#before
public void setup() {
foo = new Foo(Mockito.mock(ClassA.class);
}
}
It's really simple to do this using Mockito.
public class Foo {
private ClassA classA;
}
Test will look like this:
#RunWith(MockitoJUnitRunner.class)
public class FooTest {
#Mock
private ClassA classA;
#InjectMocks
private Foo foo = new Foo();
//Test methods
}
That's it, you have mocked ClassA!

super() in Flash Builder. WHY?

Every time I start a new actionscript class in Flash Builder it starts off the constructor with a line
super()
I have never seen this before, and it seems to have no purpose. Deleting it results in the exact same movie.
Why is it inserted into my new class and what does it do?
super() calls the constructor from the class that you're inheriting (extending).
If your inherited (base) class has no required parameters in it's constructor, you can omit it all together and flash will automatically call it before your constructor code.
You can call other functions (that are public or protected) from your base class by using the super keyword:
super.myBaseClassMethod(); //would call the method 'myBaseClassMethod' from your base class even if you had an overriden method with in this class
EXAMPLE:
package {
public class BaseClass {
public function BaseClass(){
trace("Base Class Constructed");
}
public function someBaseMethod():void {
trace("some method called from base");
}
}
}
package {
public class MyClass extends BaseClass { //this class is extending the class above
public function MyClass():void {
trace("My Class constructed");
super();
someBaseMethod();
super.someBaseMethod();
}
override public function someBaseMethod():void {
trace("Override");
}
}
}
So if you do this:
var tmp:MyClass = new MyClass();
You will get:
"My Class constructed"
"Base Class Constructed"
"override"
"some method called from base"
If you omit super(), it will be:
"Base Class Constructed"
"My Class constructed"
"override"
"some method called from base"
As a part of inheritance, super invokes the superclass or parent version of a method or constructor.
Invokes the superclass or parent version of a method or constructor.
When used within the body of a class constructor, the super()
statement invokes the superclass version of the constructor. The call
to the superclass constructor must have the correct number of
arguments. Note that the superclass constructor is always called,
whether or not you call it explicitly. If you do not explicitly call
it, a call with no arguments is automatically inserted before the
first statement in the subclass constructor body. This means that if
you define a constructor function in a subclass, and the superclass
constructor takes one or more arguments, you must explicitly call the
superclass constructor with the correct number of arguments or an
error will occur. The call to the superclass constructor, however,
does not need to be the first statement in your subclass constructor,
as was required in ActionScript 2.0.
When used in the body of an instance method, super can be used with
the dot (.) operator to invoke the superclass version of a method and
can optionally pass arguments (arg1 ... argN) to the superclass
method. This is useful for creating subclass methods that not only add
additional behavior to superclass methods, but also invoke the
superclass methods to perform their original behavior.
You cannot use the super statement in a static method.
In ActionScript, classes can extend other base classes not marked as final.
For example, MovieClip inheritance is as follows:
Sprite > DisplayObjectContainer > InteractiveObject > DisplayObject > EventDispatcher > Object
By invoking super(), you control when parent constructors are called.
package
{
import flash.display.MovieClip;
public class ExampleMovieClip extends MovieClip
{
public function ExampleMovieClip()
{
super(); // MovieClip's constructor is called
}
}
}

Struts2 JSON Plugin With Annotations

I have a Struts2 Action Class configured via annotations. All of the "normal" methods that are annotated with #Action work fine.
However, I need to add a method into the action that returns JSON.
Here is a trimmed down version of my class (dao autowired with Spring):
#Namespace("featureClass")
// define success and input actions for class here
public class FeatureClassAction extends ActionSupport {
FeatureClassDao featureClassDao;
#Autowired
public setFeatureClassDao(FeatureClassDeao featureClassDao) {
this.featureClassDao = featureClassDao;
}
List<FeatureClass> featureClasses;
// snip normal actions
#Action("/featureClassesJSON")
#JSON
public String getFeatureClassesJSON() throws Exception {
featureClasses = featureClassDao.getAll();
return SUCCESS;
}
}
Can anyone assist? If I have to go the struts.xml route, that means moving all of my other actions (which work fine) into it.
I figured I would share the answer, since anyone else with the same problem would likely also face the silence.
I created two actions: FeatureClassAction and FeatureClassJsonAction. FeatureClassAction was annotated as such:
#ParentPackage("struts-default")
#Namespace("/featureClass")
public class FeatureClassAction extends ActionSupport {
FeatureClassJsonAction is annotated like this:
#ParentPackage("json-default")
#Namespace("/featureClass")
public class FeatureClassJsonAction extends ActionSupport {
The method in the JSON Action was annotated like this:
#Action(value="featureClassesJson", results = {
#Result(name="success", type="json")
})
public String getFeatureClassesJSON() throws Exception {
Hope it helps someone.