@WebMvcTest发现状态404,服务返回null



当我使用@WebMvcTest测试我的Spring控制器时,我会遇到两个问题。

  1. MockMvc找不到正确的URL
  2. 在我添加了MockMvcBuilders.standaloneSetup()之后,mockMvc就工作了。但我的控制器throw NullPointException caused by @Autowired Service

我只是做单元测试,所以我不想使用@SpringBootTest来启动我所有的SpringBoot应用程序。我试过@InjectMock我的控制器和@Mock or @MockBean服务。它们都不起作用。那么,有人能告诉我为什么@AutowiredmockMvc找不到Controller,以及如何在没有@SpringBootTest的情况下模拟Spock单元测试中提交的内部@Autowired吗?

这是我的控制器

@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));

@WebMvcTest仅用于按应用程序测试web层,因此您需要模拟控制器中的任何依赖项并存根方法调用。更多信息

@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())
}
}

@InjectMocks无法在Spock中工作。如果我们想使用相同的函数,这里有第三部分的扩展我们可以使用@Subject和@Collaborator注释来解决此问题。注意,Spock有自己的@Subject注释。在导入包裹之前,请检查它是否在正确的包裹中

最新更新