2012-09-26 93 views
1

我的代码是API的使用者(www.abc.com/public/news/apple.json)。我得到一个json数组作为回报,然后我解析并填充到自己的数据结构中。负责这样做的代码是:单元测试Web API消费模块

public Map<String,List<NewsItem>> populateNewsArray() throws Exception 
     { 
      url = domain + newsApiStr; 
      InputStream stream = getNews(url, true); 

      //jackson library object mapper 
      ObjectMapper mapper = new ObjectMapper(); 

      //NewsApiObject class implements the structure of the json array returned. 
      List<NewsApiObject> mappedData = mapper.readValue(stream, NewsApiObject.class)); 

      //populate the properties in a HashMap. 
      //return HashMap 
    } 

    public InputStream getNews(String request, boolean bulk) throws Exception 
    { 
     URL url = new URL(request); 
     connection = (HttpURLConnection) url.openConnection();   
     connection.setDoOutput(true); 
     connection.setInstanceFollowRedirects(false); 
     connection.setRequestMethod("GET"); 
     connection.setRequestProperty("Content-Type", "text/plain"); 
     connection.setRequestProperty("charset", "utf-8"); 
     connection.connect(); 

     return connection.getInputStream(); 
    } 

正如你所看到的,我不是api的控制器,只有消费者。据说在单元测试中,不会假设发出http请求。在这种情况下,如何单元测试populateNewsArray()函数以查看对象映射是否正确(没有任何例外)并返回有效的散列表?

回答

1

您应该将getNews()提取到单独的界面中,例如,新闻阅读(虽然单词Reader已在JDK特定的含义,我喜欢这个名字......)

public interface NewsReader { 
    InputStream getNews(String request, boolean bulk) throws Exception 
} 

然后实现该接口使用HttpURLConnection按你的代码和更新代码,以允许特定的注射接口。然后,如果您需要测试代码如何处理InputStream,则可以创建一个NewsReader的模拟,它会返回一个带有众所周知内容的InputStream

请记住要实现高内聚性:您的课程不应该是HTTP客户端的流解析器。

+0

btw david,如果我确实为新闻阅读创建了一个接口,我仍然可以如何测试populateNewArray()函数?是否需要彻底更改该功能并删除getNews调用,以便它可以进行单元测试? – samach

+0

@Salmanmahmood'populateNewArray'调用'NewsReader.getNews'。你可以注入一个模拟,它返回一个(例如)包含已知JSON的'ByteArrayInputStream'。 –

+0

我将如何确保模拟对象在测试时被调用,而不是真正的实现(网络调用)? – samach

0

我会创建一个子类并覆盖方法getNews(...)。在子类中,您可以返回InputStream进行测试。
既然你不应该在一个单元测试中依赖某个外部文件,并且为了获得更好的可测试设计,我还会更改getNews(...)方法以返回某种可以由映射器进一步处理的值。