I have 3 classes:
public class SomeDAO {
// that method I'd want to catch and change
public void getObj() { ... }
}
public class MainService {
private Service2 service2;
public void doMain() {
service2.doSomethingAnother();
}
}
public class Service2 {
private SomeDAO someDAO
public void doSomethingAnother() {
someDAO.getObj();
}
}
All I need - to call doMain but with custom someDao.getObj() inside service2.doSomethingAnother():
public TestClass {
#InjectMocks
private final MainService mainService = new MainService();
#InjectMocks
private final Service2 service2 = new Service2();
#Mock
private SomeDAO someDao;
#Test
public void testMe() {
// substitution
when(someDao.getObj()).thenReturn(new MyObj());
// then I'm calling the outer method
mainService.doMain();
}
}
When running that test I have NPE in mainService.doMain(): service2 in null..
Inside of testMe object service2 is alive and not null, it has been declared as class variable and initialized.
Whether I misundersood #InjectMock behaviour?
Service2 is not injected into MainService, since it is not a mock. Therefore, the server2 attribute of your mainService object is null.
You are also trying to mock too deep. The correct way to test MainService is to mock the dependency of Service2 and not SomeDAO.
A separate test class for Service2 is better where you mock the dependency of SomeDAO.
public TestClass {
#InjectMocks
private MainService mainService;
#Mock
private Service2 service2;
#Before
public void setUp() {
initMocks(this);
}
#Test
public void testMe() {
mainService.doMain();
verify(service2).doSomethingAnother();
}
}
Related
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 have service:
#Service
class UserService {
private final Map<AbstractSomeService, CustomEnum> someMap;
public UserService(List<AbstractSomeService> someService) {
someService.forEach(service -> someMap.put(service.getCustomEnum(), service));
}
public void logicExecution() {
//code
}
}
When i am mocking as below: i am getting NullPointer:
#Mock
private SomeService someService; // Service which is extended of AbstractSomeService
#InjectMocks
private UserService userService = new UserService(Collection.singletonList(someService))
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
public void testBrokenJunit() {
userService.logicExecution(); // NULL POINTER HERE (
}
SomeService:
#Service
public class SomeService extends AbstactSomeService() {
public CustomEnum getCustomEnum() {
return CustomEnum.BROKEN_JUNIT_TEST;
}
//logic here
}
Stack trace is quite simple:
java.lang.NullPointerException: Cannot invoke "getCustomEnum()" because "service" is null
StackTrace without constructor initialization:
org.mockito.exceptions.misusing.InjectMocksException:
Cannot instantiate #InjectMocks field named 'UserService' of type '...'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : Cannot invoke "java.util.List.forEach(java.util.function.Consumer)" because "someService" is null
at
Caused by: java.lang.NullPointerException: Cannot invoke "java.util.List.forEach(java.util.function.Consumer)" because "someService" is null
at UserService.<init>
P.S.
When i am using real object of UserService, not a mock everything is ok.
But it doesn't work with #InjectMocks
Try the following in your test class (you don't need to initialize UserService with a new instance via the constructor, #InjectMocks will do that for you):
#Mock
private SomeService someService;
#InjectMocks
private UserService userService;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
public void testBrokenJunit() {
userService.logicExecution();
}
If this does not work because you have a List and not a simple SomeService you can do the following:
#Mock
private SomeService someService;
private UserService userService;
#BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
userService = new UserService(Collection.singletonList(someService));
}
#Test
public void testBrokenJunit() {
userService.logicExecution();
}
Use #MockBean to create mock objects
import org.springframework.boot.test.mock.mockito.MockBean;
#MockBean
private User user;
I have an integration which instantiates a service and that service has an Autowired dependency on a bean I'm trying to mock.
The problem is the service is getting instantiated before the autowired bean is and causing NPE. How can I ensure DependencyINeed is initialized before the MyClass in the example below?
Service
#Service
public class MyClass {
#Autowired private DependencyINeed dependency;
#Autowired
public MyClass(
#Value("${thing1}") int t1,
#Value("${thing2}") String t2) {
}
Method call yielding NPE
public class MyClass {
....
public void randomFunction() {
dependency.methodCall() <-- NPE
}
}
Test
#ContextConfiguration(classes = TestConfiguration.class)
#Import({TestConfiguration.class})
#SpringBootTest(
classes = {TestConfiguration.class, DependencyINeed.class, MyClass.class})
public class MyCoolIntegrationTest {
#Autowired private DependencyINeed dependency;
#Autowired private MyClass client;
Test Configuration
#TestConfiguration
public class MyTestConfiguration {
#MockBean private DependencyINeed dep;
#Bean
public DependencyINeed initDep() {
....
return dep;
}
}
Try to delete yout test config, and make yout Test class look like this:
#ContextConfiguration(classes = TestConfiguration.class)
#Import({TestConfiguration.class})
#SpringBootTest(
classes = {TestConfiguration.class, DependencyINeed.class, MyClass.class})
public class MyCoolIntegrationTest {
#MockBean private DependencyINeed dependency;
#Autowired private MyClass client;
#BeforeEach
public void beforeEach() {
Mockito.when(dependency.SOMEHING()).thenReturn(YOUR STUFF);
}
}
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'm trying to mock a concrete Class using Mockito. However, it remains null in the service under test.
My concrete class and Service:
//My Concrete Class
#Component("supporter")
public class Supporter
{
#Autowired
private IDriver driver;
public int someMethod(int){...}
...
}
//Service Class that uses this abstract class
public class Service implements IService
{
private ExceptionHandler exceptionHandler;
#Autowired
public void setExceptionHandler(ExceptionHandler exceptionHandler) {
this.exceptionHandler = exceptionHandler;
}
private Supporter supporter;
#Autowired
public void setSupporter(Supporter supporter) {
this.supporter = supporter;
}
public int hookItem(int arg)
{
...
//supporter is always null while mock testing <----
int count = supporter.someMethod(arg);
...
return count;
}
}
My Test Code :
public class ServiceTest extends AbstractTestMockito
{
...
IService service = null;
#Mock
private ExceptionHandler exceptionHandler;
#BeforeMethod
public void setup() {
service = new Service();
}
#Test(enabled=true)
public void shouldDoSomething()
{
Supporter supporter = Mockito.mock(Supporter.class);
given(supporter.someMethod(1)).willReturn(new Integer(10));
final int response = service.hookItem(1);
//Assert...
}
}
What could be the reason for it being null?
(My classes/service are Spring beans)
Looking at the test class, it seems like you you are not injecting the mocked Supporter instance into the service instance, e.g. try to add service.setSupporter(supporter); before calling service.hookItem(1).