I have a utility class which is a final class. There i have used injection for injecting LOGGER.
public final class Utilities {
#Inject
private static Logger.ALogger LOGGER;
private Utilities() {
//this is the default constructor. so there is no implementation
}
public static String convertToURl(string input){
try{
//do some job
}catch(IllegalArgumentException ex){
LOGGER.error("Invalid Format", ex);
}
}
}
While I writing unit testing for this method i have to mock LOGGER otherwise it will throw null pointer exception. How can i mock this LOGGER without creating instance of this class. I tried to whitebox the variable. But it only works with instances?
This code works fine. To set static field you need to pass a class to org.powermock.reflect.Whitebox.setInternalState. Please, ensure that you use PowerMock's class from the package org.powermock.reflect because Mockito has the class with the same name.
#RunWith(PowerMockRunner.class)
public class UtilitiesTest {
#Mock
private Logger.ALogger aLogger;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); // for case them used another runner
Whitebox.setInternalState(CcpProcessorUtilities.class, "LOGGER", aLogger);
}
#Test
public void testLogger() throws Exception {
Utilities.convertToURl("");
verify(aLogger).error(eq("Invalid Format"), any(IllegalArgumentException.class));
}
}
Related
Given the following classes, I would like to test the first one. Where I'm running into trouble is that because these are used in AWS Lambda, services are architected a certain way for performance reasons (e.g. container reuse) and I'm finding it impossible to even get an empty test class to run thanks to the static initializer.
public class ClassToTest {
private static ServiceA serviceA = new ServiceA();
public boolean methodToTest() {
return serviceA.someMethod();
}
}
public class ServiceA {
public ServiceA() {
this(new ServiceB());
}
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
this.someVariable = serviceB.getExpensiveServiceData();
}
}
public class ServiceB{
private static final ExpensiveService expensiveService;
private static final Map<String, Object> expensiveServiceData;
static {
expensiveService = new ExpensiveService();
expensiveServiceData = expensiveService.getData();
}
public getExpensiveServiceData() {
return expensiveServiceData.get("...");
}
}
We use Mockito for our tests. I have added PowerMockito and set up my test as follows:
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor({"com.x.ServiceA", "com.x.ServiceB"})
#PrepareForTest({ServiceA.class, ServiceB.class})
public class ClassToTestTest {
#InjectMocks private ClassToTest classToTest;
#Mock // All the classes...
public void methodToTestTest() {
// Doesn't even get here
classToTest.methodToTest();
}
}
This fails due to a NPE in getExpensiveServiceData() because I'm ignoring the static initializer and thus the Map never gets created. And I can't use Whitebox.setInternal to set the value programmatically because the class fails initialization before I have access to that. I assume ServiceA shouldn't actually be calling the real implementation of ServiceB but I don't know how to inject a mock into a mock like that in my test.
I need to mock a logger class on which the classes under test call a static method to obtain an object. Because of this I created a fake implementation of that static function as described in the official tutorial. My fake class looks like this
public class FakeLogger extends MockUp<Logger> {
#Mocked Logger logger;
#Mock
public Logger getLogger() {
return logger;
}
}
It is used in the test class:
public class MyTest {
#Mocked Logger logger;
#Before
public void setUp() throws Exception {
new FakeLogger();
}
#Test
public void test() {
new Expectations() {{
logger.warn("message");
times = 1;
}};
/*here classes under test are executed which obtain use the logger by Logger.getLogger().log("message");*/}
This implementation does not work.
The problem is that Logger.getLogger() returns null because in the fake implementation the object #Mocked Logger logger; seems to be never initialized.
Then I tried the following changes:
public class FakeLogger extends MockUp<Logger> {
#Mocked Logger logger;
public FakeLogger(Logger l) {
logger=l;
}
#Mock
public Logger getRootLogger() {
return logger;
}
}
With the test class initializing the fake implementation:
public class MyTest {
#Mocked Logger logger;
#Before
public void setUp() throws Exception {
new FakeLogger(logger);
}
#Test
public void test() {
new Expectations() {{
logger.warn("message");
times = 1;
}};
...}
When initializing the fake implementation class with the #Mocked Logger logger; object from the test class it works without a null pointer exception from an uninitialized logger object.
My conclusion would be that #Mocked Logger logger; is only initialized automatically inside the test class but not in the fake class. But according to the official tutorial #Mocked object should always be initialized automatically.
What am I missing here?
When JMockit runs, variables annotated with #Tested or #Mocked should be non-null. Effectively, JMockit is creating a MockImpl for each of them. Ignoring a lot of the complexity of your post, I focused mostly on the fact your #Mocked logger is null, which makes me strongly suspect you aren't running with JMockit. Remember that in order to run properly, you have to have "-javaagent" stuff. Without it, those #Mocked don't work and the variable will be null. I'm guessing that's what's happening.
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 want to replace an autowired class of a service in my spring boot app with a mocked implementation of that class that I created specifically for testing.
I chose to create this mocked implementation because the behaviour of this class is too complicated to mock using mockito as it requires multiple other mocks itself.
I am not able to work out how to inject this mocked implementation into the service.
Here is a minimal example of the situation:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest{
#Autowired
ComplicatedDependency complicatedDependency;
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class MockComplicatedDependency implements ComplicatedDepencency{
public MockComplicatedDependency(...){
// Inject other mocked objects into this mock
}
public String doSomthing(){
// This would be a mocked version of this function for testing
return "test";
}
}
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService(){
#InjectMock
private static ServiceIWantToTest serviceIWantToTest = new ServiceIWantToTestImpl();
#Mock
ComplicatedDependency mockComplicatedDependency;
#BeforeClass
public static void init(){
mockComplicatedDependency = new MockComplicatedDependency(...);
}
#Test
public void testAttempt(){
serviceIWantToTest.methodUsingDependency(); // This method calls complicatedDependency.doSomething() which does not run the mocked version in MockComplicatedDependency which I wanted to inject, and would always return null instead of the "test" string I put in this example.
}
}
Do you have to use Mockito annotations to setup dependencies for the class under test?
If that is not the main constraint why not just do the plain simple setup and introduce a constructor or a setter in ServiceIWantToTestImpl class for the ComplicatedDependency field and set the dependency in your test setup directly to whatever impl of ComplicatedDependency you like e.g.:
#Service
public class ServiceIWantToTestImpl implements ServiceIWantToTest {
#Autowired
ComplicatedDependency complicatedDependency;
public ServiceIWantToTestImpl() {
}
public ServiceIWantToTestImpl(ComplicatedDependency complicatedDependency) {
this.complicatedDependency = complicatedDependency;
}
#Override
public void methodUsingDependency(){
String string = complicatedDependency.doSomething();
System.out.println(string);
}
}
public class TestingTheService {
private static ServiceIWantToTestImpl serviceIWantToTest;
#BeforeClass
public static void init(){
serviceIWantToTest = new ServiceIWantToTestImpl(new MockComplicatedDependency());
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
That is one way.
To make it work with Mockito, You could to use #Spy instead of #Mock like this:
#RunWith(MockitoJUnitRunner.class)
public class TestingTheService {
#InjectMocks
private static ServiceIWantToTestImpl serviceIWantToTest = new ServiceIWantToTestImpl();
#Spy
private static ComplicatedDependency complicatedDependency = new MockComplicatedDependency();
#BeforeClass
public static void init() {
}
#Test
public void testAttempt() {
serviceIWantToTest.methodUsingDependency();
}
}
Though this is a bit of a hack. I strongly recommend that you read the JavaDoc of the #Spy annotation and make sure it's expected use is what you really need for your test.
I'm new to JMockIt and am trying to figure out/understand how to use #Injectable for a top-level MockUp class that I have already defined.
For example:
// JUnit Test Class
public class RepositoryTest {
#Tested private Repository repository;
#Injectable private ResultsAPIWrapper resultsApiWrapper;
#Test
public void testRepo(){
new ResultsApiWrapper();
assertThat(repository.doSomething(), is("done" ) );
}
}
// Class under test
public class Repository{
#Autowired private ResultsAPIWrapper resultsApiWrapper;
public String doSomething(){
return resultsApiWrapper.load();
}
}
// Mocked implementation of the ResultsAPIWrapper that I want injected into Repository
public class ResultsApiWrapperMock extends MockUp<ResultsAPIWrapper>{
#Mock
public String load(){
return "done";
}
}
If I try the above, I get an error
java.lang.IllegalArgumentException: Class already mocked: com.fw.wrappers.ResultsAPIWrapper
at com.fw.wrappers.mock.ResultsApiWrapperMock.<init>(ResultsApiWrapperMock.java:12)
at com.fw.repository.RepositoryTest.testRepo(RepositoryTest.java:38)
But If I remove the new ResultsApiWrapper() then I do not know how to specify which is the class I want to use as my mocked implementation for the autowire.
Am I misunderstanding how to do this? How can I specify that I want JMockit to autowire using my MockUp<> implementation?
I'm new too but I think something like this would work in your case...
This will mock the ResultsAPIWrapper() and not initialize any static variables and create a specific mock for load():
new MockUp<ResultsAPIWrapper>() {
#Mock
void $clinit() {
//disable static initialization
}
#Mock
public String load() {
return "done";
}
};