samach
samach

Reputation: 3394

Unit testing Web API consumer module

My code is the consumer of an API (www.abc.com/public/news/apple.json). I get a json array in return which I then parse and populate in my own data structure. the code responsible for doing this is:

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

As you can see I am not the controller of the api, only the consumer. It is said that in unit tests, one is not suppose to make http requests. In this scenario, how can I unit test the populateNewsArray() function to see if the object mapping was correct (without any exceptions) and a valid hashmap was returned?

Upvotes: 1

Views: 540

Answers (2)

markus.f
markus.f

Reputation: 1

I would create a subclass and overwrite the method getNews(...). In the subclass you then may return an InputStream for your test.
Since you should not depenend on some external file in a unit test and in order to get a better testable design I'd also change the getNews(...) method to return some kind of value which can be further processed by the mapper.

Upvotes: 0

David Grant
David Grant

Reputation: 14243

You should extract getNews() into a separate interface, e.g. NewsReader (although the word Reader has a specific meaning in the JDK, I like the name...)

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

Then implement that interface with using HttpURLConnection as per your code and update your code to allow injection of that particular interface. Then, if you need to test how your code handles an InputStream, you can create a mock of NewsReader which returns a InputStream with well-known content.

Remember to aim for high cohesion: your class shouldn't be an HTTP client and a stream parser.

Upvotes: 1

Related Questions