Состояние @WebMvcTest найдено 404 и служба возвращает значение NULL - PullRequest
2 голосов
/ 10 ноября 2019

Когда я использую @WebMvcTest для тестирования моего Spring Controller, у меня возникают два вопроса:

  1. MockMvc не может найти правильный URL-адрес
  2. После добавления MockMvcBuilders.standaloneSetup(), mockMvcсработал. Но мой контроллер throw NullPointException caused by @Autowired Service

Я просто выполняю модульное тестирование, поэтому я не хочу использовать @SpringBootTest для запуска всех приложений SpringBoot. Я попытался @InjectMock Мой контроллер и @Mock or @MockBean Сервис. Все они не работали. Так может кто-нибудь сказать мне, почему @Autowired mockMvc не может найти контроллер и как имитировать внутреннюю @Autowired, поданную в модульном тесте Спока без @SpringBootTest?

Вот мой контроллер

@RestController
@RequestMapping("/schedule/filter")
public class ScheduleObjectFilterController extends BaseController {
    @PostMapping(path="/",produces  = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String createScheduleObjectFilter(@RequestBody String body){
        BaseResponse<ResponseStatus> resp = new BaseResponse<>(ResponseStatus._200);
        try{
            List<ScheduleObjectFilterParam> paramList = parseJSONArray(body,ScheduleObjectFilterParam.class);
            resp.setStatus(scheduleObjectFilterService.createScheduleObjectFilter(paramList));
        }catch(BaseRuntimeException e){
            logger.error("Create ScheduleObjectFilter error:", e);
            resp.setException(e);
        }catch(Exception e){
            logger.error("Create ScheduleObjectFilter error:", e);
            resp.setStatus(ResponseStatus._500);
        }
         return renderJSON(resp);
    }

    @Autowired
    private ScheduleObjectFilterService scheduleObjectFilterService;

}

Вот мой Сервис и его реализация

public interface ScheduleObjectFilterService{
     ResponseStatus createScheduleObjectFilter(List<ScheduleObjectFilterParam> paramList);
}
@Service
public class ScheduleObjectFilterServiceImpl extends BaseService implements ScheduleObjectFilterService {
    public ResponseStatus createScheduleObjectFilter(List<ScheduleObjectFilterParam> paramList) {
    // some code
    }
}

Вот мой тестовый класс

@WebMvcTest(controllers = [ScheduleObjectFilterController.class])
@ActiveProfiles("local")
class ScheduleSettingControllerSpecification extends Specification{

    @Autowired
    MockMvc mockMvc

    @MockBean
    BaseController baseController

    @MockBean
    ScheduleObjectFilterService scheduleObjectFilterService

    def setup(){
        //after add next line,the mockMvc can find url,but service throw NullPointException
        //mockMvc = MockMvcBuilders.standaloneSetup(new ScheduleObjectFilterController()).build()
        scheduleObjectFilterService.createScheduleObjectFilter(_ as List) >> ResponseStatus._500
    }

    def "MvcTest"(){
        given:
        ScheduleObjectFilterParam param = new ScheduleObjectFilterParam()
        List<ScheduleObjectFilterParam> dataList = Collections.singletonList(param)
        expect:
        mockMvc.perform(post("/schedule/filter/").contentType(MediaType.APPLICATION_JSON).content(JSONObject.toJSONString(dataList)))
        .andExpect(status().isOk())
    }

}

перед добавлением MockMvcBuilders.standaloneSetup():

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /schedule/filter/
       Parameters = {}
          Headers = {Content-Type=[application/json]}
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = org.springframework.web.servlet.resource.ResourceHttpRequestHandler

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 404
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

После добавления То:

2019-11-10 11:53:22.896 [WEB] [ERROR] com.kaifa.hes.schedule.controller.ScheduleObjectFilterController.createScheduleObjectFilter() -> Create ScheduleObjectFilter error:
java.lang.NullPointerException: null
    at com.kaifa.hes.schedule.controller.ScheduleObjectFilterController.createScheduleObjectFilter(ScheduleObjectFilterController.java:47) [classes/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_201]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_201]
......

это исключение прямо на эту строку в контроллере

resp.setStatus(scheduleObjectFilterService.createScheduleObjectFilter(paramList));

Ответы [ 2 ]

2 голосов
/ 10 ноября 2019

@WebMvcTest используется только для тестирования веб-слоя приложением, поэтому вам нужно смоделировать все зависимости в контроллере и заглушить вызов метода. больше информации

@WebMvcTest(controllers = [ScheduleObjectFilterController.class])
@ActiveProfiles("local")
class ScheduleSettingControllerSpecification extends Specification{

@Autowired
MockMvc mockMvc

@MockBean
BaseController baseController

@MockBean
ScheduleObjectFilterService  scheduleObjectFilterService


def "MvcTest"(){

    when(this.scheduleObjectFilterService.createScheduleObjectFilter(ArgumentMatchers.anyList())
     .thenReturn(// custom error);    

    given:
    ScheduleObjectFilterParam param = new ScheduleObjectFilterParam()
    List<ScheduleObjectFilterParam> dataList = Collections.singletonList(param)
    expect:mockMvc.perform(post("/schedule/filter/").contentType(MediaType.APPLICATION_JSON).content(JSONObject.toJSONString(dataList)))
    .andExpect(status().isOk())
   }

}
0 голосов
/ 10 ноября 2019

@ InjectMocks не может работать в Споке. Если мы хотим использовать ту же функцию, здесь имеется расширение из третьей части Мы можем использовать аннотации @Subject и @Collaborator для решения этой проблемы. Обратите внимание , у Спока есть собственная аннотация @Subject. Прежде чем импортировать пакет, убедитесь, что он в правильных пакетах

...