title: How to test if a REST endpoint returns a number in Spring Boot?
body: <p>I have a simple controller that requests a number from some random REST service and wraps it in a JSON object. These numbers can either be integers or floating point numbers. Thus the consumers of my REST endpoint should expect a floating point value.</p>
  
  <p>This is my controller:</p>
  
  <pre><code>import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8_VALUE;
  import static org.springframework.web.bind.annotation.RequestMethod.GET;
  
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.ResponseBody;
  import org.springframework.web.client.RestTemplate;
  
  @Controller
  public class NumberController {
  
      private final RestTemplate restTemplate;
  
      @Autowired
      public NumberController(final RestTemplate restTemplate) {
          this.restTemplate = restTemplate;
      }
  
      @RequestMapping(path = "/number", method = GET, produces = APPLICATION_JSON_UTF8_VALUE)
      @ResponseBody
      public String getNumber() {
          final String number = restTemplate.getForObject("https://example.com/number", String.class);
  
          return String.format("{\"number\":%s}", number);
      }
  
  }
  </code></pre>
  
  <p>Now I want to test if the endpoint really returns the number that the REST call returns. Therefore I have written a test that uses <code>MockMvc</code>:</p>
  
  <pre><code>import static org.hamcrest.Matchers.is;
  import static org.mockito.ArgumentMatchers.any;
  import static org.mockito.ArgumentMatchers.eq;
  import static org.mockito.BDDMockito.given;
  import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
  import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
  import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  
  import java.util.stream.Stream;
  
  import org.junit.jupiter.params.ParameterizedTest;
  import org.junit.jupiter.params.provider.Arguments;
  import org.junit.jupiter.params.provider.MethodSource;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
  import org.springframework.boot.test.context.SpringBootTest;
  import org.springframework.boot.test.mock.mockito.MockBean;
  import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;
  import org.springframework.test.web.servlet.MockMvc;
  import org.springframework.web.client.RestTemplate;
  
  @SpringBootTest
  @SpringJUnitWebConfig
  @AutoConfigureMockMvc
  class NumberControllerTest {
  
      @Autowired
      private MockMvc mockMvc;
  
      @MockBean
      private RestTemplate restTemplate;
  
      @ParameterizedTest
      @MethodSource("createTestData")
      void testNumbersEndpoint(final String restServiceValue, final double expectedValue) throws Exception {
          given(restTemplate.getForObject(any(String.class), eq(String.class))).willReturn(restServiceValue);
  
          mockMvc.perform(get("/number"))
                  .andExpect(status().isOk())
                  .andExpect(jsonPath("number", is(expectedValue)));
      }
  
      private static Stream&lt;Arguments&gt; createTestData() {
          return Stream.of(Arguments.of("17", 17.0), Arguments.of("12.53", 12.53));
      }
  
  }
  </code></pre>
  
  <p>So the endpoint can either return <code>{ "number": 17 }</code> or <code>{ "number": 12.53 }</code> which is both valid JSON. With <code>.andExpect(jsonPath("number", is(expectedValue)))</code> I test if the JSON structure really contains the number that was returned by the remote REST service. Unfortunately the test fails for <code>{ "number": 17 }</code>, because <code>jsonPath("number", ...)</code> passes an integer value to the matcher.</p>
  
  <p>So how can I match both integer an floating point values?</p>
  
  <p>I was thinking of something like the following, but it doesn't work:</p>
  
  <pre><code>@ParameterizedTest
  @MethodSource("createTestData")
  void testNumbersEndpoint(final String restServiceValue, final Number expectedValue) throws Exception {
      given(restTemplate.getForObject(any(String.class), eq(String.class))).willReturn(restServiceValue);
  
      mockMvc.perform(get("/number"))
              .andExpect(status().isOk())
              .andExpect(jsonPath("number", is(expectedValue)));
  }
  
  private static Stream&lt;Arguments&gt; createTestData() {
      return Stream.of(Arguments.of("17", BigDecimal.valueOf(17)), Arguments.of("12.53", BigDecimal.valueOf(12.53)));
  }
  </code></pre>