如何用MockMvcTester断言JSON对象列表并映射为List<MyDto>
如何使用MockMvcTester对JSON对象列表进行断言?
你希望将接口响应的JSON列表映射为List<CardResponseDto>并进行断言,但当前代码转换后得到的是LinkedHashMap集合,存在未检查警告且断言无法生效(使用Spring Boot 4版本)。
你的测试代码如下:
import com.example.em_card_service.data.dto.response.CardResponseDto; import com.example.em_card_service.service.CardService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.assertj.MockMvcTester; import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @WebMvcTest(CardController.class) class CardControllerTest { @Autowired MockMvcTester mvcTester; @MockitoBean CardService cardService; @Test void findAll_givenCardsPresent_returns200_andExpectedDtos() { UUID cardId = UUID.randomUUID(); String number = "**** **** **** 1234"; CardResponseDto card = CardResponseDto.builder().id(cardId).number(number).build(); List<CardResponseDto> cards = List.of(card); given(cardService.findAll(any())).willReturn(cards); assertThat(mvcTester.get().uri("/api/admin/cards").exchange()) .hasStatusOk() .bodyJson().convertTo(List.class) .satisfies(c -> { assertThat(c).hasSize(1); // unchecked warning, besides it doesn't work: the list has LinkedHashMap, not my DTO assertThat(c).containsExactlyElementsOf(cards); }); } }
解决方案
问题根源在于Java的类型擦除:直接使用List.class时,Jackson无法识别列表的泛型元素类型,只能将JSON对象转换为LinkedHashMap。要解决这个问题,需要使用ParameterizedTypeReference来保留泛型类型信息,让Jackson正确转换为List<CardResponseDto>。
修改后的测试代码如下:
import com.example.em_card_service.data.dto.response.CardResponseDto; import com.example.em_card_service.service.CardService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.assertj.MockMvcTester; import org.springframework.core.ParameterizedTypeReference; import java.util.List; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; @WebMvcTest(CardController.class) class CardControllerTest { @Autowired MockMvcTester mvcTester; @MockitoBean CardService cardService; @Test void findAll_givenCardsPresent_returns200_andExpectedDtos() { UUID cardId = UUID.randomUUID(); String number = "**** **** **** 1234"; CardResponseDto card = CardResponseDto.builder().id(cardId).number(number).build(); List<CardResponseDto> cards = List.of(card); given(cardService.findAll(any())).willReturn(cards); // 使用ParameterizedTypeReference指定泛型列表类型 ParameterizedTypeReference<List<CardResponseDto>> typeRef = new ParameterizedTypeReference<>() {}; assertThat(mvcTester.get().uri("/api/admin/cards").exchange()) .hasStatusOk() .bodyJson().convertTo(typeRef) .satisfies(responseCards -> { assertThat(responseCards).hasSize(1); // 现在可以直接断言DTO列表,无警告且断言生效 assertThat(responseCards).containsExactlyElementsOf(cards); }); } }
关键说明
ParameterizedTypeReference是Spring提供的工具类,用于在运行时保留泛型类型信息,避免类型擦除导致的转换问题。- 通过
convertTo(typeRef)调用,Jackson会将响应的JSON数组正确反序列化为List<CardResponseDto>,而非LinkedHashMap的列表。 - 修改后不再有未检查警告,且
containsExactlyElementsOf断言可以正常生效,因为列表元素类型与预期一致。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

