2

我正在运行一个 Spring Boot 应用程序,并且我已经注册了一个新的HttpMessageConverter名为CsvCompactVenueHttpMessageConverter,这是它的代码:

@Component
public class CsvCompactVenueHttpMessageConverter extends
    AbstractHttpMessageConverter<Collection<CompactVenue>> {

    public CsvCompactVenueHttpMessageConverter() {
       super(MediaType.valueOf(TEXT_CSV));
    }

   >> message converter implementation code <<
}

它扩展AbstractHttpMessageConverter并注册为 class 上的 bean WebConfiguration

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Bean
    public CsvCompactVenueHttpMessageConverter csvCompactVenueHttpMessageConverter() {
        return new CsvCompactVenueHttpMessageConverter();
    }
}

然后我有一个名为的休息资源FoursquareResource

@RestController
@RequestMapping("/foursquare")
public class FoursquareResource {

    @Autowired
    FoursquareService foursquareService;

    @GetMapping(value = "/{location}", produces = {"application/json", "text/csv"})
    public Collection<CompactVenue> searchVenuesByLocationAndIncreasingRange(@PathVariable String location, @RequestParam(defaultValue = "1") Integer numQueries) throws FoursquareApiException, FoursquareServiceException {
        return foursquareService.searchVenuesByLocationAndIncreasingRange(location, numQueries);
    }
}

当我运行应用程序并调用http://localhost:8080/foursquare/New York NY它时,它工作正常并呈现text/csv响应。

但是当使用 RestAssured 运行测试时,@SpringBootTest我得到一个 HTTP 406 响应(因为我认为它没有正确注册HttpMessageConverterfor text/csv),这里是代码:

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class FoursquareResourceTest {

    @Mock
    FoursquareService foursquareService;

    @InjectMocks
    FoursquareResource foursquareResource;

    @Before
    public void before() throws Exception {
        CompactVenue venue = new CompactVenue();
        FieldUtils.writeField(venue, "id", "aUfmEW745", true);
        Collection<CompactVenue> venues = new ArrayList<>();
        venues.add(venue);
        when(foursquareService.searchVenuesByLocationAndIncreasingRange(any(), any())).thenReturn(venues);
    }

    @Test
    public void testSearchVenuesByLocationAndIncreasingRangeCsv() throws Exception {
        MockMvcResponse response =
        given().
            accept("text/csv").
            standaloneSetup(foursquareResource).
        when().
            get(String.format("/foursquare/%s?numQueries=%d",location,numQueries)).
        then().
            statusCode(200).
        extract().response();

        log.info(response.body().print());
    }

}

我不确定为什么在运行 Spring Boot 应用程序时会得到正确的答案,但在作为测试运行时会出现 406 错误。看起来新HttpMessageConverter的没有在测试中注册,但我不明白为什么。谢谢并恭祝安康。

4

3 回答 3

2

406 Not Acceptable只是意味着控制器无法为客户端请求的表示提供服务。text/csv在您的情况下,客户端通过发送标头指示其读取的能力Accept,但控制器无法发text/csv回。很可能缺少您的转换器。要理解为什么,重要的是要了解关于MockMvc. 目前尚不清楚您MockMvc的初始化方式,但我认为它是独立设置。请注意,这standaloneSetup会创建一个的应用程序上下文,其中未注册来自标准配置的 bean,包括您的自定义转换器。这解释了为什么代码在“正常”运行中工作,但在测试中失败。为了克服这个问题,要么使用webAppContextSetup(将启动应用程序和嵌入式 Jetty/Tomcat)注入应用程序上下文或通过调用手动设置转换setMessageConvertersStandaloneMockMvcBuilder。例如,

mockMvc = MockMvcBuilders
        .standaloneSetup(controller)
        .setMessageConverters(new SomeConverter(),
                new SomeOtherConverter())
        .build();

mockMvc然后,您只需调用即可在 REST Assure 中重用该对象

RestAssuredMockMvc.mockMvc(mockMvc);
于 2018-03-29T21:26:21.633 回答
0

有同样的问题并通过注入HttpMessageConverters并手动将它们添加到MockMvc对象来解决它:

@Autowired
private HttpMessageConverter[] httpMessageConverters;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(myController).setMessageConverters(httpMessageConverters).build();
}
于 2019-10-18T09:50:17.777 回答
0

这应该有效。它将导入您的WebConfiguration课程。

@WebMvcTest(controllers = FoursquareResource.class)
@Import(FoursquareService.class)
public class FoursquareResourceTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private FoursquareService foursquareService;

    @Test
    public void test() throws Exception {
        CompactVenue venue = new CompactVenue();
        FieldUtils.writeField(venue, "id", "aUfmEW745", true);
        Collection<CompactVenue> venues = Collections.singletonList(venue);
        when(foursquareService.searchVenuesByLocationAndIncreasingRange(any(), any())).thenReturn(venues);

        String location = "location";
        int numQueries = 4;
        MockHttpServletResponse response = mockMvc
                .perform(get("/foursquare/{location}?numQueries={numQueries}", location, numQueries).contentType("text/csv"))
                .andExpect(status().isOk())
                .andDo(print())
                .andReturn().getResponse();

        log.info(response.getContentAsString());
    }

}
于 2020-11-24T11:52:07.680 回答