Hi I have a method that takes an URL as an input and determines if it is reachable. Heres the code for that:
public static boolean isUrlAccessible(final Str
You can mock new Url instance with
whenNew(URL.class)..
Make sure you return a previously created mock object from that whenNew call.
URL mockUrl = Mockito.mock(URL.class);
whenNew(URL.class).....thenReturn(mockUrl );
Then you can add behavior to your mock as you want.
URL is final class. To mock final class we can use PowerMockito with Junit. To mock final class we need to annotate Test class with @RunWith(PowerMockRunner.class) and @PrepareForTest({ URL.class })
@RunWith(PowerMockRunner.class)
@PrepareForTest({ URL.class })
public class Test {
@Test
public void test() throws Exception {
URL url = PowerMockito.mock(URL.class);
HttpURLConnection huc = Mockito.mock(HttpURLConnection.class);
PowerMockito.when(url.openConnection()).thenReturn(huc);
assertTrue(url.openConnection() instanceof HttpURLConnection);
}
}
But in the line PowerMockito.when(url.openConnection()).thenReturn(huc); following error is thrown:
java.lang.AbstractMethodError
at java.net.URL.openConnection(URL.java:971)
at java_net_URL$openConnection.call(Unknown Source)
In order to get rid of this error we can modify our Test class as shown below:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ URL.class })
public class Test {
@Test
public void test() throws Exception {
public class UrlWrapper {
URL url;
public UrlWrapper(String spec) throws MalformedURLException {
url = new URL(spec);
}
public URLConnection openConnection() throws IOException {
return url.openConnection();
}
}
UrlWrapper url = Mockito.mock(UrlWrapper.class);
HttpURLConnection huc = Mockito.mock(HttpURLConnection.class);
PowerMockito.when(url.openConnection()).thenReturn(huc);
assertTrue(url.openConnection() instanceof HttpURLConnection);
}
}
Visit: https://programmingproblemsandsolutions.blogspot.com/2019/04/abstractmethoderror-is-thrown-on.html
Found the solution. First mock the URL class, then Mock the HttpURLConnection and when url.openconnection() is called, return this mocked HttpURLConnection object and finally set its response code to 200. Heres the code:
@Test
public void function() throws Exception{
RuleEngineUtil r = new RuleEngineUtil();
URL u = PowerMockito.mock(URL.class);
String url = "http://www.sdsgle.com";
PowerMockito.whenNew(URL.class).withArguments(url).thenReturn(u);
HttpURLConnection huc = PowerMockito.mock(HttpURLConnection.class);
PowerMockito.when(u.openConnection()).thenReturn(huc);
PowerMockito.when(huc.getResponseCode()).thenReturn(200);
assertTrue(r.isUrlAccessible(url));
}
In order to mock java.net.URL class through mockito
library, you need to perform the following steps:
mock-maker-inline
text into the file. code:
package myproject;
import org.junit.Test;
import java.net.HttpURLConnection;
import java.net.URL;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class Test {
@Test
public void test() throws Exception {
URL url = mock(URL.class);
HttpURLConnection huc = mock(HttpURLConnection.class);
when(url.openConnection()).thenReturn(huc);
assertTrue(url.openConnection() instanceof HttpURLConnection);
}
}
It's much simpler with the JMockit mocking API (and even simpler with no mocking):
import java.io.*;
import java.net.*;
import org.junit.*;
import static org.junit.Assert.*;
import mockit.*;
public final class ExampleURLTest {
public static final class ClassUnderTest {
public static boolean isUrlAccessible(String urlToValidate) throws IOException {
HttpURLConnection huc = null;
int responseCode;
try {
URL url = new URL(urlToValidate);
huc = (HttpURLConnection) url.openConnection();
huc.setRequestMethod("HEAD");
huc.connect();
responseCode = huc.getResponseCode();
}
finally {
if (huc != null) {
huc.disconnect();
}
}
return responseCode == 200;
}
}
// Proper tests, no unnecessary mocking ///////////////////////////////////////
@Test
public void checkAccessibleUrl() throws Exception {
boolean accessible = ClassUnderTest.isUrlAccessible("http://google.com");
assertTrue(accessible);
}
@Test(expected = UnknownHostException.class)
public void checkInaccessibleUrl() throws Exception {
ClassUnderTest.isUrlAccessible("http://inaccessible12345.com");
}
@Test
public void checkUrlWhichReturnsUnexpectedResponseCode(
@Mocked URL anyURL, @Mocked HttpURLConnection mockConn
) throws Exception {
new Expectations() {{ mockConn.getResponseCode(); result = -1; }};
boolean accessible = ClassUnderTest.isUrlAccessible("http://invalidResource.com");
assertFalse(accessible);
}
// Lame tests with unnecessary mocking ////////////////////////////////////////
@Test
public void checkAccessibleUrl_withUnnecessaryMocking(
@Mocked URL anyURL, @Mocked HttpURLConnection mockConn
) throws Exception {
new Expectations() {{ mockConn.getResponseCode(); result = 200; }};
boolean accessible = ClassUnderTest.isUrlAccessible("http://google.com");
assertTrue(accessible);
}
@Test(expected = UnknownHostException.class)
public void checkInaccessibleUrl_withUnnecessaryMocking(
@Mocked URL anyURL, @Mocked HttpURLConnection mockConn
) throws Exception {
new Expectations() {{ mockConn.connect(); result = new UnknownHostException(); }};
ClassUnderTest.isUrlAccessible("http://inaccessible12345.com");
}
}
(Verified with JMockit 1.47 on JDKs 8 & 9.)
Although this thread has some good suggestion, but if any of you is not interested to use those third-party libraries here is a quick solution.
public class MockHttpURLConnection extends HttpURLConnection {
private int responseCode;
private URL url;
private InputStream inputStream;
public MockHttpURLConnection(URL u){
super(null);
this.url=u;
}
@Override
public int getResponseCode() {
return responseCode;
}
public void setResponseCode(int responseCode) {
this.responseCode = responseCode;
}
@Override
public URL getURL() {
return url;
}
public void setUrl(URL url) {
this.url = url;
}
@Override
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public void disconnect() {
}
@Override
public boolean usingProxy() {
return false;
}
@Override
public void connect() throws IOException {
}
}
And, this how you can set the desired behaviour
MockHttpURLConnection httpURLConnection=new MockHttpURLConnection(new URL("my_fancy_url"));
InputStream stream=new ByteArrayInputStream(json_response.getBytes());
httpURLConnection.setInputStream(stream);
httpURLConnection.setResponseCode(200);
Note: It just mock 3 methods from HttpUrlConnection
and if you are using more method you need to make sure those are mock as well.