I have a test class which is testing an other class method
Other class is structured like this
#Component
public abstract class ParentOpManager{
#Autowired
private ProcessorRequestWrapper processorRequestWrapper;
#Autowired
private XYProcessor xyProcessor;
}
#Component("childManager")
public class ChildOperationManager extends ParentOpManager{
}
public abstract class ParentClass{
protected final RequestWrapper requestWrapper;
protected final ParentOpManager parentOpManager;
public ParentClass(final RequestWrapper requestWrapper, final ParentOpManager parentOpManager){
this.requestWrapper = requestWrapper;
this.parentOpManager = parentOpManager;
}
}
further I have, child classes extending this class
public class ChildClass extends ParentClass{
#Autowired
private NinjaManager ninjaManager;
#Autowired
public ChildClass(final RequestWrapper requestWrapper, #Qualifier("childManager")final ParentOpManager parentOpManager){
super(requestWrapper, parentOpManager);
}
public void methodA() throws Exception {
Request item = requestWrapper.findItem(); // Problem place 1
}
public void methodB() throws Exception {
Request item = ninjaManager.findItem(); // Problem place 2
}
}
I need to test methods of ChildClass. For this I have written a test class.
//#RunWith(MockitoJunitRunner.class)
//#ContextConfiguration
public class TestClass{
#Mock
ChildOperationManager chOpManager;
#Mock
RequestWrapper requestWrapper;
#InjectMocks
ChildClass childObject;
#Before
public void setup(){
MockitoAnnotations.initMocks(this);
}
#Test
public void testSomeMethodA() throws Exception{
childObject.methodA();
}
}
So, the problem is when I am class methodA from test class, requestWrapper is NULL. I can not understand why this is happening ?
EDIT:
If i do like
#Mock
ChildOperationManager chOpManager = new ChildOperationManager();
#Mock
RequestWrapper requestWrapper;
#InjectMocks
ChildClass childObject = new childObject(requestWrapper, chOpManager);
Problem seams to be resolved. There is some other problem which might be some permission issue. But do you think doing this way is good approach ?
Your error is this:
#Autowired
public ChildClass(final RequestWrapper requestWrapper, #Qualifier("childManager")final ParentOpManager parentOpManager){
super(requestWrapper, parentOpManager);
}
public void methodA() throws Exception {
Request item = requestWrapper.findItem(); // this requestWrapper is null
}
You don't assign the requestWrapper reference in the child. So it remains null.
You should just remove the member variable requestWrapper and parentOpManager from the child. this way, you'll use the parent's one, which is initialized.
Problem is that Mockito tried to inject mock via constructor in first step.
public class DefaultInjectionEngine {
public void injectMocksOnFields(Set<Field> needingInjection, Set<Object> mocks, Object testClassInstance) {
MockInjection.onFields(needingInjection, testClassInstance)
.withMocks(mocks)
.tryConstructorInjection() <-- Here
.tryPropertyOrFieldInjection()
.handleSpyAnnotation()
.apply();
}
}
And if it found proper constructor, it doesn't try to inject mocks via property or field.
In your case you have constructor for ChildClass, which was picked by Mockito, but you don't initialize a fields in ChildClass.
As workaround, you can resolve it in this way (just don't use mockito injections):
RequestWrapper wrapper;
ChildOperationManager childOperationManager;
ChildClass childObject;
#Before
public void setUp() {
wrapper = Mockito.mock(RequestWrapper.class);
childOperationManager = Mockito.mock(ChildOperationManager.class);
childObject = new ChildClass(wrapper, childOperationManager );
}
Related
I'm a bit new to mocking, but I have a class (lets call it ClassA) with methods including one that returns a put response after sending an item to a database.
This class is called in another class (lets say ClassB), but classB's methods do not return the response from ClassA.
Given the following structure for ClassA and ClassB:
private final DatabaseClientFactory dbClientFactory;
private final DatabaseClient dbClient;
... other instance vars ...
public ClassA() {
ClassA(new ..params, new dbClientFactory());
}
public ClassA(...some parameters ... DatabaseClientFactory dbClientFactory) {
....
this.dbClientFactory = dbClientFactory;
this.dbClient = this.dbClientFactory.get();
}
public PutResponse methodA() {
...
dbClient.put(...);
}
and ClassB:
public ClassB(...some params..., ClassA aClass) {
}
public void methodB() {
aClass.methodA();
...more random code
}
I've tried to set up the mock equivalent to this logic:
public class classBTest {
#Mock
private ClassA aClass = new ClassA();
private ClassB bClass;
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
bClass = spy(ClassB(aClass));
#Test
public void test() throws Exception {
bClass.methodB();
when(aClass.methodA(any())).thenReturn(PutResponse.newBuilder().build());
verify(aClass, Mockito.times(1)).methodA(any());
}
I kept getting an error that
Wanted but not invoked:
aClass.methodA(<any>);
Actually, there were zero interactions with this mock.
So I tried a few things
I tried changing the constructor call of bClass to be bClass = spy(ClassB(mock(ClassA.class)))
I tried adding when(classA.methodA(any())).thenReturn(PutResponse.newBuilder().build());
to the setUp method.
I tried setting up spy on an instance of ClassA, with mocked parameters
I tried using #InjectMocks but ended up with a null pointer exception.
But now I'm stuck
Any suggestions?
*Note that ClassA has an empty constructor by default
I have the following set of classes:
public abstract class ParentClass {
#Autowired
private SomeService service;
protected Item getItem() {
return service.foo();
}
protected abstract doSomething();
}
#Component
public ChildClass extends ParentClass {
private final SomeOtherService someOtherService;
#Override
protected doSomething() {
Item item = getItem(); //invoking parent class method
.... do some stuff
}
}
Trying to test the Child class:
#RunWith(MockitoJUnitRunner.class)
public class ChildClassTest {
#Mock
private SomeOtherService somerOtherService;
#Mock
private SomerService someService; //dependency at parent class
#InjectMocks
private ChildClass childClass;
public void testDoSomethingMethod() {
Item item = new Item();
when(someService.getItem()).thenReturn(item);
childClass.doSomething();
}
}
The matter is that I'm always getting a NullPointerException because the parent dependency (SomeService) is always null.
Also tried:
Mockito.doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
return new Item();
}
}).when(someService).getItem();
And using Spy, without any success.
Thanks for your hints.
One option is using ReflectionTestUtils class to inject the mock. In the code bellow I've executed the unit tests with JUnit 4.
#RunWith(MockitoJUnitRunner.class)
public class ChildClassTest {
#Mock
private SomeService someService;
#Test
public void test_something() {
ChildClass childClass = new ChildClass();
ReflectionTestUtils.setField(childClass, "service", someService);
when(someService.foo()).thenReturn("Test Foo");
assertEquals("Child Test Foo", childClass.doSomething());
}
}
I'm using mokito to inject a mock. This object extends a class that requires a contructor with arguments. How to mock this object that requires constructor arguments and pass this arguments as mock too?
Example class
public abstract class AbstractClassRequireContructor{
protected AbstractClassRequireContructor(Object param) {
}
public class ClassA extends AbstractClassRequireContructor{
public ClassA(Object param) {
super(param); // required by super class
}
}
Test class
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA; // requires contructor from super class
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
// how to inject mocked argument?
classA = new ClassA(paramMockToBeAddedByConstructor); // this doesn't work
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue); // use injectMock class normally
}
}
Is there any another strategy to work arroung this better?
Drop the instantiation of a new ClassA object. It should work without it as follows:
#ExtendWith(MockitoExtension.class)
public class ClassATest{
#Mock
private Object paramMockToBeAddedByConstructor;
#InjectMocks
private ClassA classA;
#BeforeEach
void setup{
when(paramMockToConstructor.anyMethod()).thenReturn(anyValue);
}
#Test
void test(){
when(classA.anyMethod()).thenReturn(anyValue);
}
}
I have a class name ServiceLocator
public class ServiceLocator implements ApplicationContextAware {
private transient ApplicationContext _applicationContext;
private static ServiceLocator _instance = new ServiceLocator();
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_instance._applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return _instance._applicationContext;
}
public static Object findService(String serviceName) {
return _instance._applicationContext.getBean(serviceName);
}
}
I am trying to use that class to find Service into Approver class methods
public class ApproverService extends AbstractDataService implements IApproverService {
public void updateCompletedInboxStatus(String status) {
IInboxService inboxService = (IInboxService)ServiceLocator.findService("inboxService");
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
With that code i am trying to write Junit with PowerMockRunner
#RunWith(PowerMockRunner.class)
#PrepareForTest({ApproverService.class})
public class ApproverServiceTest {
#InjectMocks
ApproverService approverService;
#Mock
IInboxService inboxService;
#Mock
ServiceLocator serviceLocator;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
RequestAccessHeader reqHdr = new RequestAccessHeader();
reqHdr.setRequestStatus(AccessConstants.REQ_STATUS_HOLD_INT);
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(serviceLocator.findService("inboxService")).thenReturn(inboxService);
approverService.updateCompletedInboxStatus(status);
}
}
But I am getting null pointer
java.lang.NullPointerException
at com.alnt.fabric.common.ServiceLocator.findService(ServiceLocator.java:25)
at com.alnt.access.approver.service.ApproverServiceTest.updateCompletedInboxStatus(ApproverServiceTest.java:80)
Please help me to find the solution for that issue.
The static method is obviously not mocked.
The problem is most probably because you haven't add the to-be-mocked class in #PrepareForTest
Change it to #PrepareForTest({ApproverService.class, ServiceLocator.class})
Off-topics:
Although it compiles, calling static method by instance reference is not a good practice. Therefore the line should be when(ServiceLocator.findService(...)).thenReturn(inboxService).
Another problem is, you tried to use Singleton pattern but in wrong way. A singleton is suppose to return you an instance so the caller can call its instance method. Your findService is preferably an instance method and to be called as ServiceLocator.getInstance().findService(...). To further improve, unless you really need it to be a singleton, you should make it a normal object instance and inject to objects that need it (given you are already using Spring, I see no reason making a Singleton)
The setup for the static method is not mocked correctly
#RunWith(PowerMockRunner.class)
#PrepareForTest({ServiceLocator.class}) //Prepare static class for mock
public class ApproverServiceTest {
#Mock
IInboxService inboxService;
#Mock
InboxItem item;
#InjectMocks
ApproverService approverService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
PowerMockito.mockStatic(ServiceLocator.class);
when(ServiceLocator.findService("inboxService")) //<-- NOTE static call
.thenReturn(inboxService);
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
Reference Mocking Static Method
The subject under test should actually be refactored to avoid the service locator anit-pattern / code smell and should follow explicit dependency principle via constructor injection.
public class ApproverService extends AbstractDataService implements IApproverService {
private IInboxService inboxService;
#Autowired
public ApproverService(IInboxService inboxService){
this.inboxService = inboxService;
}
public void updateCompletedInboxStatus(String status) {
InboxItem inboxItem = inboxService.getInboxItem("test");
inboxItem.setWorkItemStatus(status);
inboxService.saveInboxItem(inboxItem);
}
}
That way the subject class is genuine about what it needs to perform its function correctly,
And the test can then be refactored accordingly
#RunWith(PowerMockRunner.class)
public class ApproverServiceTest {
#Mock
IInboxService inboxService;
#Mock
InboxItem item;
#InjectMocks
ApproverService approverService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateCompletedInboxStatus() {
//Arrange
String status = "test";
when(inboxService.getInboxItem("test")).thenReturn(item);
//Act
approverService.updateCompletedInboxStatus(status);
//...
}
}
I think there is either a basic misunderstanding on my part with how when works, or more specifically how Mockito is working.
I have a service class that has a utility class injected via constructor. The utility class has some other dependencies autowired by constructor as well.
A service class method calls several methods in the utility class. The test uses when/thenReturn statements on the called utility methods. When I make a call on the service method, I get an NPE on a utility method called with a null parameter. But I expected parameters set in the when clause to be set. Code below:
#Service
public class ServiceClass {
private Utility utility;
public ServiceClass(Utility utility) {
this.utility = utility;
}
public serviceMethod(MyDocument myDocument, List<Attachment> attachments) {
SomeType variable1;
OtherType variable2;
List<String> stringList;
long time;
time = utility.method1(variable1, variable2);
stringList = utility.method2(myDocument, attachments.get(0));
...
}
#Service
public class Utility {
private Dependency1 depend1;
private Dependency2 depend2;
public Utility(Dependency1 depend1, Dependency2 depend2) {
this.depend1 = depend1;
this.depend2 = depend2;
}
public long method1(SomeType var1, OtherType var2) {
....
}
public List<String> method2(MyDocument myDoc, Attachment attach) {
....
}
Now the test code looks as follows:
public TestClass {
private ServiceClass serviceClass;
#Mock
private Depend1 depend1;
#Mock
private Depend2 depend2;
#InjectMocks
private Utility utility;
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Before
public void setup() {
serviceClass = new ServiceClass(utility);
}
#Test
public testServiceMethod() {
long time = System.currentTimeMillis();
MyDocument doc = new MyDocument();
List<Attachments> attachments = Arrays.asList(new Attachment(...), new Attachment(...));
SomeType some = new SomeType();
OtherType other = new OtherType();
when(utility.method1(some, other)).thenReturn(time);
when(utility.method2(doc, attachments.get(0)).thenReturn(Arrays.asList(new String("stg 1"), new String("stg 2"));
String resp = serviceClass.serviceMethod(doc, attachments);
assertEquals("service completed", resp);
}
}
But when utility.method2 is called, myDocument shows as null. I was expecting that it would be an instance of MyDocument.
Do I have something misconfigured? Am I missing a concept here? All help appreciated!
Thanks.
UPDATE
Corrected the arguments to the serviceMethod.
The ServiceClass is the class you are testing, so you should anotate with #Mock only the dependencies of this class in your test, in your case the utility attribute, remove Depend1 and Depend1 declarations. The setup method is not necessary, you can anotate serviceClass in your test with #InjectMocks instead, it take cares of the injections automatically. And finally, your TestClass need the #RunWith(MockitoJunitRunner.class) to make everything work if it's not there.
#RunWith(MockitoJunitRunner.class)
public class TestClass{
#InjectMocks
private ServiceClass serviceClass;
#Mock
private Utility utility;
}
This is a basic definition for your TestClass, the test itself looks correct, but can be improved to use ArgumentMatchers on the "when" clause and add a verify clause using ArgumentCaptor to validate the parameters.