测试 URL 和 URL 连接
Testing URL and URLConnection
我不知道如何在没有真正连接到真正的 url 到服务器的情况下测试它。
我已经阅读了一些关于在这种情况下使用 Mockito 的文章并尝试四处搜索,但找不到好的教程或建议我应该如何为 URL 和 [=58= 进行 jUnit 测试]我项目中的连接。
这是我在尝试测试时遇到问题的代码:
public JSONObject getJSONObj()
throws MalformedURLException, IOException, ParseException {
String jsonString;
try (InputStream is = getURLConnection("RealUrlStringGoesHere").getInputStream();) {
jsonString = IOUtils.toString(is);
}
return (JSONObject) JSONValue.parseWithException(jsonString);
}
public URLConnection getURLConnection(String urlStr) throws MalformedURLException, IOException {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
return conn;
}
这里也有我用的导入,如果有人想知道:
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
已编辑
感谢您的回答,但我似乎对此完全迷失了。也许我想的太复杂了,但是单元测试对我来说是个新东西,但真的很想学习更多。
是的,我尝试测试 getJSONObj 方法,但是那些 URL 和 URL 连接让我很难理解如何通过 "faking" 来测试我的方法相信这真的需要联系。
无法理解您的真正意思,所以这是我尝试按照您所说的 Jeff Bowman 执行操作时的当前代码。 (仍在使用那个大字符串,因为我试图先用当前样式完成它,然后在工作后用 Reader 获得更好的性能。)
Discusser.java
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
public class Discusser implements URLOpener {
public JSONObject getJSONObj() throws IOException, ParseException {
String jsonString;
try (InputStream is = openURL("RealUrlStringGoesHere");) {
jsonString = IOUtils.toString(is);
}
return (JSONObject) JSONValue.parseWithException(jsonString);
}
@Override
public InputStream openURL(String urlStr) throws IOException {
URL url = new URL(urlStr);
URLConnection urlConnection = url.openConnection();
return urlConnection.getInputStream();
}
}
URLOpener.java
import java.io.IOException;
import java.io.InputStream;
public interface URLOpener {
InputStream openURL(String urlStr) throws IOException;
}
这个测试几乎没有用,因为我认为我尝试使用模拟的方式是完全错误的。 (当 discusser.getJSONObj() 时返回 null)
DiscusserTest.java
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import org.json.simple.JSONObject;
import org.junit.Test;
import org.mockito.Mockito;
public class DiscusserTest {
@Test
public void testGetJSONObj() throws Exception {
JSONObject expectedJSONObject = createExpected();
ByteArrayInputStream inputForMock = new ByteArrayInputStream(generateJSONString().getBytes("UTF-8"));
// Should I mock like this or...
Discusser discusser = Mockito.mock(Discusser.class);
Mockito.when(discusser.openURL("asd")).thenReturn(inputForMock);
//
assertEquals(expectedJSONObject, discusser.getJSONObj());
}
private String generateJSONString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"id\":\"123\",");
sb.append("\"name\":\"test\"");
sb.append("}");
return sb.toString();
}
@SuppressWarnings("unchecked")
private JSONObject createExpected() {
JSONObject obj = new JSONObject();
obj.put("id", 123);
obj.put("name", "test");
return obj;
}
}
您或其他人能否提供指导/示例,说明应该如何测试讨论器中的 getJSONObj() 方法?
您可以在测试中启动一个服务器并针对该服务器进行测试。您可以为此使用 MockServer。
你想测试什么?
如果您尝试测试与真实服务器的交互是否正确发生,那么再多的模拟也无济于事。您想编写一个集成测试。
如果您尝试测试通过 Java 的 URL 连接发生的交互,那么模拟服务器可能会工作 。不过,我认为这不一定是有用的东西,因为 Java URLConnection 框架是经过充分测试的第三方代码。
看起来这里最可测试的组件是 getJSONObj(),其中不太可测试的部分是将 URL 转换为 InputStream 的函数。让它成为你的界面,而不是:
interface URLOpener {
InputStream openURL(String url);
}
到那时,您可以在生产代码中使用非常简单的实际实现,或者传入一个非常简单的模拟,returns 一个 ByteArrayInputStream。
旁注:如果使用 JSONValue.parse(Reader)
而不是尝试构造一个包含整个 JSON 文件的大字符串,您可能会发现性能更好。这不会干扰模拟,因为您可以改用 StringReader。
/* in prod, within your actual URLOpener */
return new InputStreamReader(urlConnection.getInputStream());
/* in test, for your mock URLOpener */
when(mockUrlOpener.openURL(expectedURL)).thenReturn(new StringReader(testJSON));
JSONValue value = JSONValue.parse(new BufferedReader(readerFromUrl));
我设法让它工作,这是结果。如果您有改进的想法或其他建议,我很高兴得到它们。
我在 Discusser 中为 URLOpener 添加了 setter,这样我就可以很容易地把那个模拟的放在那里。
Discusser.java
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
public class Discusser implements URLOpener {
private URLOpener urlOpener;
public JSONObject getJSONObj() throws IOException, ParseException {
JSONObject jsonObj;
try (InputStream is = openURL("RealUrlStringGoesHere");) {
jsonObj = (JSONObject) JSONValue.parse(new InputStreamReader(is));
}
return jsonObj;
}
@Override
public InputStream openURL(String urlStr) throws IOException {
return urlOpener.openURL(urlStr);
}
public void setURLOpener(URLOpener urlOpener) {
this.urlOpener = urlOpener;
}
}
DiscusserTest.java
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.json.simple.JSONObject;
import org.junit.Test;
public class DiscusserTest {
@Test
public void testGetJSONObj() throws Exception {
Discusser discusser = new Discusser();
discusser.setURLOpener(createMockURLOpener());
assertEquals(createExpected(), discusser.getJSONObj());
}
private URLOpener createMockURLOpener() throws IOException {
URLOpener mockUrlOpener = mock(URLOpener.class);
ByteArrayInputStream input = new ByteArrayInputStream(generateJSONString().getBytes("UTF-8"));
when(mockUrlOpener.openURL("RealUrlStringGoesHere")).thenReturn(input);
return mockUrlOpener;
}
private String generateJSONString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"id\":\"123\",");
sb.append("\"name\":\"test\"");
sb.append("}");
return sb.toString();
}
@SuppressWarnings("unchecked")
private JSONObject createExpected() {
JSONObject obj = new JSONObject();
obj.put("id", "123");
obj.put("name", "test");
return obj;
}
}
URLOpener.java
import java.io.IOException;
import java.io.InputStream;
public interface URLOpener {
InputStream openURL(String urlStr) throws IOException;
}
我不知道如何在没有真正连接到真正的 url 到服务器的情况下测试它。
我已经阅读了一些关于在这种情况下使用 Mockito 的文章并尝试四处搜索,但找不到好的教程或建议我应该如何为 URL 和 [=58= 进行 jUnit 测试]我项目中的连接。
这是我在尝试测试时遇到问题的代码:
public JSONObject getJSONObj()
throws MalformedURLException, IOException, ParseException {
String jsonString;
try (InputStream is = getURLConnection("RealUrlStringGoesHere").getInputStream();) {
jsonString = IOUtils.toString(is);
}
return (JSONObject) JSONValue.parseWithException(jsonString);
}
public URLConnection getURLConnection(String urlStr) throws MalformedURLException, IOException {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
return conn;
}
这里也有我用的导入,如果有人想知道:
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
已编辑
感谢您的回答,但我似乎对此完全迷失了。也许我想的太复杂了,但是单元测试对我来说是个新东西,但真的很想学习更多。
是的,我尝试测试 getJSONObj 方法,但是那些 URL 和 URL 连接让我很难理解如何通过 "faking" 来测试我的方法相信这真的需要联系。
无法理解您的真正意思,所以这是我尝试按照您所说的 Jeff Bowman 执行操作时的当前代码。 (仍在使用那个大字符串,因为我试图先用当前样式完成它,然后在工作后用 Reader 获得更好的性能。)
Discusser.java
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
public class Discusser implements URLOpener {
public JSONObject getJSONObj() throws IOException, ParseException {
String jsonString;
try (InputStream is = openURL("RealUrlStringGoesHere");) {
jsonString = IOUtils.toString(is);
}
return (JSONObject) JSONValue.parseWithException(jsonString);
}
@Override
public InputStream openURL(String urlStr) throws IOException {
URL url = new URL(urlStr);
URLConnection urlConnection = url.openConnection();
return urlConnection.getInputStream();
}
}
URLOpener.java
import java.io.IOException;
import java.io.InputStream;
public interface URLOpener {
InputStream openURL(String urlStr) throws IOException;
}
这个测试几乎没有用,因为我认为我尝试使用模拟的方式是完全错误的。 (当 discusser.getJSONObj() 时返回 null)
DiscusserTest.java
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import org.json.simple.JSONObject;
import org.junit.Test;
import org.mockito.Mockito;
public class DiscusserTest {
@Test
public void testGetJSONObj() throws Exception {
JSONObject expectedJSONObject = createExpected();
ByteArrayInputStream inputForMock = new ByteArrayInputStream(generateJSONString().getBytes("UTF-8"));
// Should I mock like this or...
Discusser discusser = Mockito.mock(Discusser.class);
Mockito.when(discusser.openURL("asd")).thenReturn(inputForMock);
//
assertEquals(expectedJSONObject, discusser.getJSONObj());
}
private String generateJSONString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"id\":\"123\",");
sb.append("\"name\":\"test\"");
sb.append("}");
return sb.toString();
}
@SuppressWarnings("unchecked")
private JSONObject createExpected() {
JSONObject obj = new JSONObject();
obj.put("id", 123);
obj.put("name", "test");
return obj;
}
}
您或其他人能否提供指导/示例,说明应该如何测试讨论器中的 getJSONObj() 方法?
您可以在测试中启动一个服务器并针对该服务器进行测试。您可以为此使用 MockServer。
你想测试什么?
如果您尝试测试与真实服务器的交互是否正确发生,那么再多的模拟也无济于事。您想编写一个集成测试。
如果您尝试测试通过 Java 的 URL 连接发生的交互,那么模拟服务器可能会工作
看起来这里最可测试的组件是 getJSONObj(),其中不太可测试的部分是将 URL 转换为 InputStream 的函数。让它成为你的界面,而不是:
interface URLOpener {
InputStream openURL(String url);
}
到那时,您可以在生产代码中使用非常简单的实际实现,或者传入一个非常简单的模拟,returns 一个 ByteArrayInputStream。
旁注:如果使用 JSONValue.parse(Reader)
而不是尝试构造一个包含整个 JSON 文件的大字符串,您可能会发现性能更好。这不会干扰模拟,因为您可以改用 StringReader。
/* in prod, within your actual URLOpener */
return new InputStreamReader(urlConnection.getInputStream());
/* in test, for your mock URLOpener */
when(mockUrlOpener.openURL(expectedURL)).thenReturn(new StringReader(testJSON));
JSONValue value = JSONValue.parse(new BufferedReader(readerFromUrl));
我设法让它工作,这是结果。如果您有改进的想法或其他建议,我很高兴得到它们。
我在 Discusser 中为 URLOpener 添加了 setter,这样我就可以很容易地把那个模拟的放在那里。
Discusser.java
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
public class Discusser implements URLOpener {
private URLOpener urlOpener;
public JSONObject getJSONObj() throws IOException, ParseException {
JSONObject jsonObj;
try (InputStream is = openURL("RealUrlStringGoesHere");) {
jsonObj = (JSONObject) JSONValue.parse(new InputStreamReader(is));
}
return jsonObj;
}
@Override
public InputStream openURL(String urlStr) throws IOException {
return urlOpener.openURL(urlStr);
}
public void setURLOpener(URLOpener urlOpener) {
this.urlOpener = urlOpener;
}
}
DiscusserTest.java
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.json.simple.JSONObject;
import org.junit.Test;
public class DiscusserTest {
@Test
public void testGetJSONObj() throws Exception {
Discusser discusser = new Discusser();
discusser.setURLOpener(createMockURLOpener());
assertEquals(createExpected(), discusser.getJSONObj());
}
private URLOpener createMockURLOpener() throws IOException {
URLOpener mockUrlOpener = mock(URLOpener.class);
ByteArrayInputStream input = new ByteArrayInputStream(generateJSONString().getBytes("UTF-8"));
when(mockUrlOpener.openURL("RealUrlStringGoesHere")).thenReturn(input);
return mockUrlOpener;
}
private String generateJSONString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append("\"id\":\"123\",");
sb.append("\"name\":\"test\"");
sb.append("}");
return sb.toString();
}
@SuppressWarnings("unchecked")
private JSONObject createExpected() {
JSONObject obj = new JSONObject();
obj.put("id", "123");
obj.put("name", "test");
return obj;
}
}
URLOpener.java
import java.io.IOException;
import java.io.InputStream;
public interface URLOpener {
InputStream openURL(String urlStr) throws IOException;
}