Unable to mock System class static method using PowerMockito - java

Even though I have read the manual and gone through multiple answers for Powermock, could not mock a static method for my use case.
Class:
#Component
public class SCUtil{
public void createSC(){
try {
String host = InetAddress.getLocalHost().getHostAddress();
// ...
// ...
// ...
} catch (UnknownHostException e) {
log.error("Exception in creasting SC");
throw new ServiceException(e);
}
}
}
Test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest( InetAddress.class )
public class SCUtilTest {
#InjectMocks
private SCUtil scUtil;
private Event event;
#Before
public void beforeEveryTest () {
event = new InterventionEvent();
}
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC(event);
}
}
Here, the test is failing as no exception is being thrown:
java.lang.AssertionError: Expected exception:
com.example.v1.test.selftest.errorhandling.ServiceException
I have wrecked more than a couple of hours in this and still have not gotten it to work. What am I doing wrong?
Thank you for all the help in advance :)

java.net.InetAddress is a system class. The caller of the system class should be defined in #PrepareForTest({ClassThatCallsTheSystemClass.class}).
See documentation.
The way to go about mocking system classes are a bit different than
usual though. Normally you would prepare the class that contains the
static methods (let's call it X) you like to mock but because it's
impossible for PowerMock to prepare a system class for testing so
another approach has to be taken. So instead of preparing X you
prepare the class that calls the static methods in X!
Please note #InjectMocks annotation does not inject static mocks, it can be removed.
Example of working test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(SCUtil.class)
public class SCUtilTest {
private SCUtil scUtil = new SCUtil();
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () throws UnknownHostException {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC();
}
}

Related

Mockito: Cannot throw exception in Java Unit Test

I have the following service and test methods and I am trying the code execute catch (ApplicationException e) { } block.
public abstract class ApplicationException extends RuntimeException {
// ....
}
public void create(Request request) {
try {
// ...
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
}
}
Here is the test method:
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
// variable defnitions and stubbings (code omitted)
willAnswer( invocation -> { throw new RuntimeException("abc msg"); })
.given(productService).create(request);
// or
// doThrow(new RuntimeException()).when(productService).create(request);
// service method call
productService.create(Request request);
}
When I debug the code, I get error on doThrow line:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!
So, how can I solve the problem?
As #Jesper mentioned in comment you are not using Mockito properly.
For your test case you need to test that your ProductService.create method will handle an error in a given scenario. Let's imagine that your code looks like this.
class ProductService {
private SomeOtherService someOtherService;
public void create(Request request) {
try {
someOtherService.execute();
} catch (ApplicationException e) {
// I want the code hits this block and check the values in here
enter code here
throw new MyException(e); // Here you can do something else
}
}
So someOtherService.execute can throw ApplicationException. We need to test if our ProductService.create will catch that exception and do some processing. In the example we will just throw a different type of exception.
#Mock
private SomeOtherService mockOtherService;
#InjectMocks
private ProductServiceImpl productService;
#Test
public void test() {
doThrow(new ApplicationException()).when(someOtherService).execute();
given(productService.create(request)).willThrow(new MyException());
}
So main difference from your example is that we are telling the SomeOtherService mock what it should do when execute method is called. This is allowed and Mockito knows how to work with mocks.
In your example you were trying to pass a real object not a mock. #InjectMock annotation is a shorthand for this
this.productService = new ProductService(mockSomeOtherService);
So it creates a new object with its dependency mocked. More about this you can find here https://stackoverflow.com/a/16467893/2381415.
I didn't run this code or test it so do not C/P it.
Hope it helps you understand what was wrong with your approach.

Mocking void method returning a null pointer exception

I am facing an issue when trying to unit test a function call. The call is failing for a void method invocation messageProducer.sendMessage() even though it has been stubbed.
Please find below a simplified snapshot of my code. I am using a doAnswer() stubbing to mock the void method (based on earlier answers on StackOverflow).
I even tried the other options of doThrow() and doNothing() stubbings, but they also fail with the same NPE when calling the stubbed method :(.
Appreciate if someone could suggest a solution/workaround. Many thanks.
Test Class
// Test class
#RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
    #Mock
    private MessageProducer messageProducer;
 
    #InjectMocks
    private MigrationRequestServiceImpl migrationRequestService;
 
#Before
    public void init() {
     MockitoAnnotations.initMocks(this);
    }
#Test
public void sendRetriggerRequest() throws Exception {
// Below two stubbings also not Work, NPE encountered!
//doNothing().when(messageProducer).sendMessage(any(), anyLong());
//doThrow(new Exception()).doNothing().when(messageProducer).sendMessage(any(), anyLong());
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
System.out.println("called with arguments: " + Arrays.toString(args));
return null;
}
}).when(messageProducer).sendMessage(any(EMSEvent.class), anyLong());
try {
// Gets Null pointer exception
migrationRequestService.retriggerRequest(emsRetriggerRequest);
}
catch (Exception ex) {
fail(ex.getMessage());
}
}
Implementation Class being tested, the stubbed method call from this class throws NPE as indicated in code comments
#Service
#Transactional
public class MigrationRequestServiceImpl implements MigrationRequestService {
#Autowired
MessageProducer messageProducer;
#Override
public void retriggerRequest(EMSRetriggerRequestData emsRetriggerRequestData) throws EMSException {
// Does a bunch of things
submitTaskScheduledEventsToQueue(taskList);
}
private void submitTaskScheduledEventsToQueue(List<Task> taskList) {
System.out.println("Debugging 1...");
taskList.stream().forEach(task -> {
System.out.println("Debugging 2...");
Map<String, Object> detailsMap = new HashMap<String, Object>();
EMSEvent event = new EMSEvent(EMSEventType.TASK_SCHEDULED);
event.setDetails(detailsMap);
LOGGER.info(ContextRetriever.getServiceContext(), ContextRetriever.getRequestContext(), "*** Re-submitting Task: *** " + task.getId());
// ****Gives a null pointer exception here****
messageProducer.sendMessage(event, eventsConfigProperties.getScheduledEventDelay());
});
System.out.println("Debugging 3...");
}
}
Autowired class that is injected into the test class and whose method is throwing the NPE
#Service
public class MessageProducer {
private static final Logger logger = LoggerFactory.getLogger(MessageProducer.class);
private final RabbitTemplate rabbitTemplate;
#Autowired
public MessageProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}
public void sendMessage(EMSEvent emsEvent, Long delay) {
// code to send message to RabbitMQ here
}
}
Do not use doAnswer if you simply want to capture the arguments and process/verify them in some way. Mockito has a defined feature called ArgumentCaptor that is designed just for that. By using it you will not need to haggle around with that void method the way you do:
#Mock private MessageProducer messageProducer;
#Captor private ArgumentCaptor<Event> eventCaptor;
#Captor private ArgumentCaptor<Long> longCaptor;
#InjectMocks
private MigrationRequestServiceImpl migrationRequestService;
#Test
public void sendRetriggerRequest() throws Exception {
// When
migrationRequestService.retriggerRequest(emsRetriggerRequest);
// Then
verify(messageProducer).sendMessage(eventCaptor.capture(), longCaptor.capture());
Event e = eventCaptor().getValue();
Long l = longCaptor().getValue();
}
Thank you Maciej for the answer. Actually I don't want to do anything with the arguments, I just need to skip this method call. I just used doAnswer with some dummy code since doNothing() or doThrow() did not work with this method.
I was able to resolve the issue however. One of the Autowired components (eventsConfigProperties) for the class which was being injected with Mocks (MigrationRequestServiceImpl) was not being mocked in the test class! Thanks to #daniu for pointing this out.
The stack trace from Mockito was not very helpful in debugging the issue, it just gave a null pointer exception right on the method invocation which caused me to think there may be other issues!
Apologize for the mistake, my bad, but thank you and good to know about the ArgumentCaptor, would probably need it for future testing!
Had to add this entry which was autowired into the MigrationRequestService class.
// Test class
#RunWith(MockitoJUnitRunner.class)
public class RetriggerRequestTest {
#Autowired
EventsConfigProperties eventsConfigProperties;
// Other declarations
}

Powermock can't mock static class

I have a class with code similar to :
public class class1{
private static final ConfigurationService config = Util.getInstance(ConfigurationService.class);
private SendQueueMessages sender;
public void start() throws LifecycleException{
LOGGER.info("Starting");
final ActiveMq activemq = config.getConfiguration().getActiveMq();
sender = new SendQueueMessages(activemq.getQueueName());
}
}
Elsewhere in the program Guice is being used to bind the configuration service and Util like so:
Util.register(new ThingICantChange(){
#Override
protected void configure (){
super.configure();
bind(ConfigurationService.class).to(ConfigurationServiceImpl.class).asEagerSingleton();
}
});
Is this possible to unit test? I was initially trying to use JUnit 5 and mockito, but it became apparent that I needed to mock static classes/methods (IoCUtils) and switched to JUnit4 for PowerMock.
I have tried:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Util.class)
public class Class1Test{
#Test
public void canStart(){
mockStatic(Util.class);
when(Util.getInstance(ConfigurationService.class)).thenReturn(new ConfigurationService);
Class1 class = new Class1();
class.start();
//etc.
}
}
However this just gives me an error about Util not prepared for test. Changing mockStatic() to PowerMockito.spy() did get me to the when, but then throws a null pointer error.
I found a solution, though I have mixed feelings about it.
Using the Util.register (the 2nd code block) I registered a configuration service implementation that created the mock objects. This worked and let me test the start() method, but feels kind of against the idea of a unit test.
public class ConfigServiceTest implements ConfigurationService{
#Override
public Configuration getConfiguration() {
Configuration conf = mock(Configuration.class);
ActiveMq amq = mock(ActiveMq.class);
when(amq.getQueueName()).thenReturn("test");
when(amq.getBrokerUrl()).thenReturn("http://127.0.0.1:61616?soTimeout=1000");
when(conf.getActiveMq()).thenReturn(amq);
return conf;
}
//other methods just allowed to return null
}
Then in the test:
Util.register(new thingICantChange(){
#Override
protected void configure (){
super.configure();
bind(ConfigurationService.class).to(ConfigServiceTest.class).asEagerSingleton();
}
});
class1 service = new class1();
service.start();
Assert.assertEquals(true, true);
start is void and not int a new thread so Assert.assertEquals(true,true) is the best anyone around me knew to check that start ran. Mockito/PowerMock times(1) would require a mock of class1 which seems rather counter to a unit test to see IF it can run.

Singleton returning new instance when accessed from test method

I am using Junit 4.12 with PowerMock 1.6 with Mockito. I have also used PowerMockRule library as described here. I am trying to execute initialization code for all of my test cases exactly once as described in this SO Thread. Its executing the initialization code exactly one time however, if I do ServiceInitializer.INSTANCE inside test method it returns me new object. I am not able to understand this behavior. Does anyone have any idea why this is happening? If I execute my code without PowerMockRule Library and run my test with PowerMockRunner then it works fine but in that case my ClassRule is not getting executed.
public class ServiceInitializer extends ExternalResource {
public static final TestRule INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this); //Print Address #3702c2f1
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final TestRule serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(ServiceInitializer.INSTANCE);//Print Address #54d41c2b
}
}
Update
I printed the classloader for the classes and it turns out for first print statement the classloder was sun.misc.Launcher$AppClassLoader and for the second print statement the classloder was org.powermock.core.classloader.MockClassLoader. How can I solve this?
You don't have a singleton. You have a static INSTANCE variable. Keep in mind that one of those can exist for every classloader you have.
Instead make an enum of ServiceInitializer, like so
public enum ServiceInitializer {
INSTANCE;
// rest of class goes here
}
And rely on the JVM's language contracts to ensure the singleton.
Or, better yet, write your code to handle situations where more than one ServiceInitializer can exist, but it just happens that your program only uses one instance. This is the ideal choice, allowing you to alternate between the real ServiceInitializer and a mock if desired.
Edwin is correct; this is an issue with PowerMock creating a new ClassLoader for every test. I strongly recommend refactoring your code so it can be tested without PoeerMock and switch to Mockito.
These books may be helpful
Working Effectively With Legacy Code
Refactoring to Patterns
In the mean time, you can reference ServiceInitializer from your base class:
public class ServiceInitializer extends ExternalResource {
public static final ServiceInitializer INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this);
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final ServiceInitializer serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(serviceInitializer);
}
}
Well I finally found the work around for this problem. As explained in my question my class was getting loaded by two different class loaders and thus causing problems for me. In order to resolve my issue I used #PowerMockIgnore annotation in order to defer its loading as follows:
#PowerMockIgnore({"com.mypackage.*"})
class BaseTest{
// Stuff goes here
}
This annotation tells PowerMock to defer the loading of classes with the names supplied to value() to the system classloader. You can read about this annotation from here.

Mock/Stub super constructor invocation in Java for unit testing

I want to unit-test my class with JUnit and EasyMock. It extends android.location.Location. But I am always getting Stub! exception because most of Android methods are not available in JVM runtime.
public class MyLocation extends Location {
public MyLocation(Location l) {
super(l);
}
public boolean methodUnderTest() {
return true;
}
}
I've tried to mock constructor invocation using Powermock, but it looks like it does not work for super calls. My test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Location.class)
public class MyLocationTest {
#Test
public void methodUnderTestReturnsTrue() throws Exception {
Location locationMock = EasyMock.createMock(Location.class);
expectNew(Location.class, Location.class).andReturn(locationMock);
MyLocation myLocation = new MyLocation(locationMock);
assertTrue(myLocation.methodUnderTest());
}
}
An exception I am getting:
java.lang.RuntimeException: Stub!
at android.location.Location.<init>(Location.java:6)
Obviously the solution is to execute this test in Android runtime (i.e. start Android Simulator). But I don't like this approach because it takes quite a few time to start such test suite. Is there a way to stub super invocation or probably there's better approach in testing such implementations?
Taken straight from the Powermocks documentation.
Testing can then be done without invoking the EvilParent constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(ExampleWithEvilParent.class)
public class ExampleWithEvilParentTest {
#Test
public void testSuppressConstructorOfEvilParent() throws Exception {
suppress(constructor(EvilParent.class));
final String message = "myMessage";
ExampleWithEvilParent tested = new ExampleWithEvilParent(message);
assertEquals(message, tested.getMessage());
}
}

Categories

Resources