【问题标题】:Testing URL and URLConnection测试 URL 和 URLConnection
【发布时间】:2015-10-09 07:56:28
【问题描述】:

如果没有真正连接到服务器的真实网址,我不知道应该如何测试它。

我已经阅读了几篇关于在这种情况下使用 Mockito 的文章并尝试四处搜索,但找不到好的教程或建议我应该如何在我的项目中为 URL 和 URLConnection 进行 jUnit-test。

这是我在尝试测试时遇到问题的代码:

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-method,但是那些 URL 和 URLConnection 让我很难理解如何通过“假装”它来测试我的方法,以相信它确实需要连接。

无法理解您的真正意思,所以这是我尝试按照您所说的 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;
}

这个测试几乎没有用,因为我认为我如何尝试使用模拟是完全错误的。 (当讨论者.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;
    }
}

您或其他人能否提供指导/示例应如何测试 Discusser 中的 getJSONObj()-method?

【问题讨论】:

    标签: java url junit mockito urlconnection


    【解决方案1】:

    您可以在您的测试中启动一个服务器并针对该服务器进行测试。您可以为此使用MockServer

    【讨论】:

    • 也感谢您的回答。将为此 MockServer 添加书签以备将来使用。
    【解决方案2】:

    我设法让它工作,这是结果。如果您有改进的想法或其他建议,我很高兴收到。

    我在 Discusser 中为 URLOpener 添加了 setter,所以我可以很容易地把那个 mocked 放在那里。

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

    【讨论】:

      【解决方案3】:

      你想测试什么?

      如果您尝试测试与真实服务器的交互是否正确发生,那么再多的模拟也无济于事。你会想要编写一个集成测试。

      如果您尝试测试通过 Java 的 URLConnection 发生的交互,那么模拟服务器可能会工作the way Stefan Birkner describes。不过,我认为这不一定有用,因为 Java URLConnection 框架是经过严格测试的第三方代码。

      看起来这里最可测试的组件是 getJSONObj(),其中不可测试的部分是将 URL 转换为 InputStream 的函数。改为将其作为您的界面:

      interface URLOpener {
        InputStream openURL(String url);
      }
      

      此时,您可以在生产代码中使用非常简单的真实实现,或者传入一个返回 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));
      

      【讨论】:

      • 感谢您的回答。我编辑了我的第一篇文章以包含当前代码,因此您可以更清楚地了解我的问题。我不确定我是否完全按照您的意思理解您的建议。
      猜你喜欢
      • 2014-01-31
      • 2014-10-29
      • 1970-01-01
      • 2015-06-25
      • 1970-01-01
      • 2013-01-29
      • 1970-01-01
      • 2013-02-03
      • 1970-01-01
      相关资源
      最近更新 更多