java - Java - 如何模拟URL连接

我有一个方法,它接受一个URL作为输入,并确定它是否可访问,下面是该代码的代码:


public static boolean isUrlAccessible(final String urlToValidate) throws WAGNetworkException {


 URL url = null;


 HttpURLConnection huc = null;


 int responseCode = -1;


 try {


 url = new URL(urlToValidate);


 huc = (HttpURLConnection) url.openConnection();


 huc.setRequestMethod("HEAD");


 huc.connect();


 responseCode = huc.getResponseCode();


 } catch (final UnknownHostException e) {


 throw new WAGNetworkException(WAGConstants.INTERNET_CONNECTION_EXCEPTION);


 } catch (IOException e) {


 throw new WAGNetworkException(WAGConstants.INVALID_URL_EXCEPTION);


 } finally {


 if (huc != null) {


 huc.disconnect();


 }


 }


 return responseCode == 200;


 }



我想使用PowerMockito对isUrlAccessible()方法进行单元测试,我觉得我需要使用whenNew()来模仿URL和调用url.openConnection()时的创建,返回另一个模拟的HttpURLConnection对象,但我不知道如何实现这个?谁能帮助我实现这个目标?

时间:

找到了解决方案,首先模拟URL类,然后模拟httpurlConnection当调用URL,openConnection时返回这个模拟的httpurlConnection对象,最后将它响应代码设置为200,下面是代码:


@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));



 }



你可以模拟新的Url实例


whenNew(URL.class)..



确保从新调用时返回先前创建的模拟对象。


URL mockUrl = Mockito.mock(URL.class);


whenNew(URL.class).....thenReturn(mockUrl );



然后你可以根据需要向mock添加行为。

URL是final类,为了模拟final类,我们可以在Junit中使用PowerMockito 。 要模拟final类,我们需要使用@RunWith(PowerMockRunner.class)和@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);


 }


}




但是,在PowerMockito.when(url.openConnection()). thenReturn(huc)中; 抛出以下错误:


java.lang.AbstractMethodError


 at java.net.URL.openConnection(URL.java:971)


 at java_net_URL$openConnection.call(Unknown Source) 



为了消除此错误,我们可以修改我们的测试类,如下所示:


@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);


 }


}



为了通过mockito库模拟java.net.URL类,你需要执行以下步骤:

  • 在src/tests/resources目录中创建一个名为'mockito-extensions'的目录,
  • 在文件夹中创建文本文件,命名为org.mockito.plugins.MockMaker,并将mock-maker-inline文本放入文件中,
  • 你可以像下面这样模拟该类:

代码:


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);


 }


}



使用JMockit模拟API更简单(甚至更简单):


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");


 }


}



(在JDK 8上使用JMockit 1.47验证

...