Powermockito not mocking URL constructor in URI.toURL() method

1 answer

This unit test is failing.

package com.abc;  import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner;  import java.net.URI; import java.net.URL;  import static org.junit.Assert.assertEquals;  @RunWith(PowerMockRunner.class) @PowerMockIgnore("javax.management.*") @PrepareForTest({URI.class}) public class ITest2 {     @Test     public void test5() throws Exception {         URI uri = new URI("http://www.google.com");          final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource("static/abc.png"); //EXISTS          PowerMockito.whenNew(URL.class).withArguments(                 "http://www.google.com")                 .thenReturn(resourceUrl);          URL url = uri.toURL(); // <--- At this point, url should be == resourceUrl          assertEquals(resourceUrl, url); // <--- url is http://www.google.com and not ".../static/abc.png"     } } 

This unit test is failing.

java.lang.AssertionError:  Expected :file:/Users/hidden/target/classes/static/abc.png Actual   :http://www.google.com <Click to see difference> 

Do you know why url != resourceUrl? What am I missing?

Here's the code of URI.toURL():

public URL toURL()     throws MalformedURLException {     if (!isAbsolute())         throw new IllegalArgumentException("URI is not absolute");     return new URL(toString()); } 

Using Mockito 2.15 & Powermock 2.0.7.

Thank you.

Update:

Adding these don't help either. Just hacking away.

PowerMockito.whenNew(URL.class).withArguments(         eq("http://www.google.com"))         .thenReturn(resourceUrl);  PowerMockito.whenNew(URL.class).withArguments(Mockito.anyString()).thenReturn(resourceUrl); PowerMockito.whenNew(URL.class).withArguments(any()).thenReturn(resourceUrl); PowerMockito.whenNew("java.net.URL").withArguments(any()).thenReturn(resourceUrl);  PowerMockito.whenNew(URL.class).withParameterTypes(String.class)         .withArguments("http://www.google.com")         .thenReturn(resourceUrl);  PowerMockito.whenNew(URL.class).withAnyArguments().thenReturn(resourceUrl);  PowerMockito.whenNew(URL.class).withNoArguments().thenReturn(resourceUrl); 

All answers to this question, which has the identifier 61239329

The best answer:

From the FAQ:

Question:

I cannot mock classes in from java.lang, java.net, java.io or other system classes, why?

Answer:

This is because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. Since PowerMock 1.2.5 there's a work-around, please have a look at this simple example to see how it's done.

Note that the link to the example there is a dead one, it should be this one instead.


user674669 wrote:

I am intercepting the constructor of URL class which happens in URI class.

You are trying to do that. However this fails silently (and the real object is created instead).

user674669 wrote:

So, I am preparing URI using PrepareForTest annotation.

java.net.URI is a system class. As mentioned above PowerMockito is not able to manipulate the bytecode for it, so it won't have any effect. You will have to adjust the bytecode of a different class instead, which implies that you need to define a different class in the @PrepareForTest annotation.


A working example for the case mentioned from the linked article:

Tested with powermock 2.0.7, mockito 3.3.3, junit 4

public class ClassUnderTest {     public InputStream method(boolean param, URI uri) throws Exception {         String scheme = param ? "https" : "http";         URI replacedUri = new URI(scheme, uri.getAuthority(), uri.getPath(), uri.getQuery(), uri.getFragment());         return replacedUri.toURL().openStream();     } } 
@RunWith(PowerMockRunner.class) @PrepareForTest(ClassUnderTest.class) public class MyTest {       @Test     public void testMethod() throws Exception {           URI uri = new URI("blah://localhost");         FileInputStream fis = new FileInputStream(new File(".", "existing.file"));          URI uriMock = PowerMockito.mock(URI.class);          URL urlMock = PowerMockito.mock(URL.class);           PowerMockito.whenNew(URI.class).withAnyArguments().thenReturn(uriMock);          Mockito.when(uriMock.toURL()).thenReturn(urlMock);          Mockito.when(urlMock.openStream()).thenReturn(fis);           ClassUnderTest testObject = new ClassUnderTest();          InputStream is = testObject.method(false, uri);          Assert.assertEquals(fis, is);     } } 

This is working because the bytecode of the ClassUnderTest is modified and the defined mock is placed there instead of the creation of a real URI object.

Last questions

how do i remove the switch on my home screen?
how to edit the JS date and time to update atuomatically?
How to utilize data stored in a multidimensional array
Powermockito not mocking URL constructor in URI.toURL() method
Android Bluetooth LE Scanner only scans when phone's Location is turned on in some devices
docker wordpress container can't connect to mysql container
How can I declare a number in java that is more than 64-bits? [duplicate]
Optaplanner solutionClass entityCollectionProperty should never return null error when simple JSON object passed to controller
Anylogic, get the time a pedestrain is in a queue
How do I fix this syntax issue with my .flex file?
Optimizing query in PHP
How to find the highest number of a column and print two columns of that row in R?
Ideas on “Error: Type com.google.firebase.iid.zzav is referenced as an interface from com.google.firebase.messaging.zzd”?
JCIFS SmbFile.exists() and SmbFile.isDirectory() return false when it exists and I can listFiles()
PHP total order
Laravel booking system design
neural net - undefined column selected
How to indicate y axis does not start from 0 in ggplot?
Fragments in backStack
Spinner how to change the data