Chris
Chris

Reputation: 899

Spring RestTemplate.execute(), how to stub the response that gets passed in to my callback function?

I have the following code. Dictionary is just a wrapper for a List of type String.

public Dictionary getDictionary(int size, String text) {
    return restTemplate.execute(url, HttpMethod.GET, null, response -> {
        BufferedReader br = new BufferedReader(new InputStreamReader(response.getBody()));
        List<String> words = new ArrayList<>();
        String line;
        while((line = br.readLine()) != null){
            if (isMatch(line, size, text)){
                words.add(line.toLowerCase());
            }
        }
        br.close();
        return new Dictionary(words);
    });
}

private boolean isMatch(String word, int size, String text) {
    if(word.length() != size) {
        return false;
    }
    return wordUtil.isAnagram(word, text);
}

I'm having a hard time test this method at the moment. The HTTP call just returns a list of words in plain text with new line separators.

I want to write a test where I can stub the response.getBody().

I.e. I want response.getBody() to return a bunch of words, and I'll assert that the returned Dictionary only contains the words that are of size size and that are an anagram of the string text.

Is this possible?

Thanks

Upvotes: 1

Views: 470

Answers (1)

Lesiak
Lesiak

Reputation: 26066

It is possible to stub a method taking a callback, and execute the callback when the stub is called.

The idea is to:

  • use when / thenAnswer to execute code when the stubbed method is called
  • use invocationOnMock passed to thenAnswer to get the callback instance
  • call the callback, providing necessary params
@Test
void testExecute() {
    String responseBody = "line1\nline2";
    InputStream responseBodyStream = new ByteArrayInputStream(responseBody.getBytes());
    ClientHttpResponse httpResponse = new MockClientHttpResponse(responseBodyStream, 200);
    when(restTemplate.execute(any(URI.class), eq(HttpMethod.GET), eq(null), any())).thenAnswer(
      invocationOnMock -> {
          ResponseExtractor<MyDictionary> responseExtractor = invocationOnMock.getArgument(3);
          return responseExtractor.extractData(httpResponse);
      }
    );
    MyDictionary ret = aController.getDictionary(1, "text");
    // assert ret against your expecations
}

Having said that, this seems to be a bit complicated for the task at hand. IMHO you will be better off if you separate the logic of dealing with Http from your business logic. Extract a method taking your inputStream, and test that separately.

Upvotes: 2

Related Questions