Java 如何模拟 URL 连接
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25334139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to mock a URL connection
提问by Nemin
Hi I have a method that takes an URL as an input and determines if it is reachable. Heres the code for that:
嗨,我有一种方法可以将 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;
}
I want to unit test the isUrlAccessible() method using PowerMockito
. I feel that I will need to use whenNew()
to mock the creation of URL
and the when url.openConnection()
is called, return another mock HttpURLConnection
object. But I have am not sure how to implement this? Am I on the right track? Can anyone help me in implementing this?
我想使用PowerMockito
. 我觉得我将需要使用whenNew()
来模拟的创建URL
和url.openConnection()
调用时,返回另一个模拟HttpURLConnection
对象。但我不确定如何实现这一点?我在正确的轨道上吗?任何人都可以帮助我实现这一点吗?
采纳答案by Nemin
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:
找到了解决办法。首先模拟 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));
}
回答by Sezin Karli
You can mock new Url instance with
您可以模拟新的 Url 实例
whenNew(URL.class)..
Make sure you return a previously created mock object from that whenNew call.
确保从 whenNew 调用中返回先前创建的模拟对象。
URL mockUrl = Mockito.mock(URL.class);
whenNew(URL.class).....thenReturn(mockUrl );
Then you can add behavior to your mock as you want.
然后,您可以根据需要向模拟添加行为。
回答by ?brahim Gündüz
In order to mock java.net.URL class through mockito
library, you need to perform the following steps:
为了通过mockito
库模拟 java.net.URL 类,您需要执行以下步骤:
- Create a directory, named 'mockito-extensions' in src/tests/resources directory.
- Create text a text file in the folder, named org.mockito.plugins.MockMaker and put
mock-maker-inline
text into the file. - you can mock the class like the following:
- 在 src/tests/resources 目录中创建一个名为“mockito-extensions”的目录。
- 在文件夹中创建一个文本文件,命名为 org.mockito.plugins.MockMaker 并将
mock-maker-inline
文本放入文件中。 - 你可以像下面这样模拟这个类:
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);
}
}
回答by Pranab Thakuria
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 })
URL 是最后一类。为了模拟 final 类,我们可以将 PowerMockito 与 Junit 一起使用。要模拟最终类,我们需要使用 @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);
}
}
But in the line PowerMockito.when(url.openConnection()).thenReturn(huc);following error is thrown:
但是在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)
In order to get rid of this error we can modify our Test class as shown below:
为了摆脱这个错误,我们可以修改我们的 Test 类,如下所示:
@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
访问:https: //programmingproblemsandsolutions.blogspot.com/2019/04/abstractmethoderror-is-thrown-on.html
回答by Rogério
It's much simpler with the JMockit mocking API (and even simpler with no mocking):
使用 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");
}
}
(Verified with JMockit 1.47 on JDKs 8 & 9.)
(在 JDK 8 和 9 上使用 JMockit 1.47 验证。)
回答by minhaz
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.
注意:它只是模拟 3 个方法HttpUrlConnection
,如果您使用更多方法,则需要确保这些方法也是模拟的。