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

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());
}

Related

Why Powermock PrepareForTest prevent mock inject?

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;
}

Test case for entity manager

Getting a null pointer exception on Mockito.when for the below code line.
when(entityManager.createQuery(any(String.class)).setParameter(any(String.class), any(String.class)).getSingleResult()).thenReturn("2");
Trying to mock entity manager which is declared as
#Mock
private EntityManager entityManager;
Any help to resolve this?
Complete test class
#RunWith(MockitoJUnitRunner.class)
public class ASDAOImplTest {
#InjectMocks
ASDAOImpl asdaoImpl=new ASDAOImpl();
#Mock
private EntityManager entityManager;
#Before
public void setUp()
{
ReflectionTestUtils.setField(asdaoImpl,"capLimit", 1);
}
#Test
#Ignore
public void validateCappingTest()
{
when(entityManager.createQuery(any(String.class)).setParameter(any(String.class), any(String.class)).getSingleResult()).thenReturn("2");
asdaoImpl.validateCapping("2");
}
}
Edit: Ah, spoke to soon. The error is here...
when(entityManager.createQuery(any(String.class)).setParameter(...)
entityManager is a mock. Per default, a mock will return null. So, entityManager.createQuery(...) will return null. Calling setParameter on null is a NPE.
What you need to insert is a query mock...
#Mock
private Query query;
...
// when createQuery is called, return the mocked query object (instead of null)
when(entityManager.createQuery(any(String.class)).thenReturn(query);
// make sure that setParameter returns this query object back (would otherwise also be NPE)
when(query.setParameter(any(String.class), any(String.class)).thenReturn(query);
// And return the desired result from getSingleResult
when(query.getSingleResult()).thenReturn("2");
Old answer:
Hard to say without the complete code, but a guess would be that you are misssing the Mockito initialization (the part that actually creates object for the variables annotated with #Mock). This can be done in at least two ways:
// Run the whole test with the Mockito runner...
#RunWith(MockitoJUnitRunner.class)
public class MyTestClass { ...
or...
// Do the Mockito initialization "manually"
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
Both ways will lead to Mockito creating all the objects where the variables are annotated with #Mock (it also handles #InjectMocks, etc.).
If this doesn't help, you will have to post more of your test class, otherwise probably noone can help.

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!

make #jsonignore use a setter over a isMethod?

This is my class
public class HouseJPAImpl implements House {
public RoomJPAImpl room;
public RoomJPAImpl getRoom(){
return this.room;
}
public void setRoom(RoomJPAImpl room){
this.room = room;
}
#Override
public boolean isRoom(){
return false;
}
}
My code gets confused with getRoom and isRoom.
Caused by: java.lang.IllegalArgumentException: Conflicting getter definitions for property "room": com.shared.model.restimpl.jpa.HouseJPAImpl#getRoom(0 params) vs com.shared.model.restimpl.jpa.HouseJPAImpl#isRoom(0 params)
I tried putting the #jsonignore on the isRoom method but then i dont get the room property in JSON.
Is there a way to use the getRoom over isRoom?
First of all, this is something that Jackson 2.3 will handle gracefully (see https://github.com/FasterXML/jackson-databind/issues/238).
But until it gets released, there are 2 main ways to handle this:
Add #JsonIgnore on isRoom(), but keep #JsonProperty on getRoom()
Change visibility settings to filter out all isXxx() methods: can either set global settings (ObjectMapper has something like setVisibility), or use annotation #JsonAutoDetect on classes
If this is an isolated case, you are probably better off by just using first one.

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.