我已经编写了一个典型的三层Spring Boot REST API,并正在为其构建测试。API 本身工作正常,但我在让控制器测试工作时遇到了问题。返回的主体为空,因为控制器层返回的对象为 null。以下是主要的依赖关系。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
我已经模拟了服务层,但测试中的 when 语句似乎没有像我预期的那样触发。
这是测试本身:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class VehicleControllerTest {
@MockBean
VehicleServiceImpl vService;
@Mock
HttpServletRequest mockRequest;
@Mock
Principal mockPrincipal;
@Autowired
MockMvc mockMvc;
Vehicle vehicle1;
@BeforeEach
public void setUp() throws ItemNotFoundException {
vehicle1 = new Vehicle();
vehicle1.setVin("5YJ3E1EA5KF328931");
vehicle1.setColor("black");
vehicle1.setDisplayName("Black Car");
vehicle1.setId(1L);
}
@Test
@WithMockUser("USER")
public void findVehicleByIdSuccess() throws Exception {
//Given **I think the problem is here***
when(vService.findVehicleById(any(),any(),any())).thenReturn(vehicle1);
//When
this.mockMvc.perform(get("/vehicles/1")).andDo(print())
//Then
.andExpect(status().isOk());
}
}
下面是相应的控制器方法:
@Secured("ROLE_USER")
public class VehicleController {
@JsonView(VehicleView.summary.class)
@GetMapping("/vehicles/{id}")
public Vehicle findVehicleById(@PathVariable Long id, Principal principal,
HttpServletRequest request) throws ItemNotFoundException {
log.info("In controller " +LogFormat.urlLogFormat(request,principal.getName()));
return vehicleService.findVehicleById(id,principal, request);
}
这是MockHTTPServletResponse。它的状态为 200,但正文为空
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
作为参考,这是我尝试模拟的服务方法
@Override
public Vehicle findVehicleById(Long id, Principal principal, HttpServletRequest request) throws ItemNotFoundException {
Optional<Vehicle> vehicle = vehicleRepository.findByIdAndUserId(id,principal.getName());
if (vehicle.isPresent()){
return vehicle.get();
} else {
throw new ItemNotFoundException(id,"vehicle");
}
}
我已经尝试了不同版本的Springboot,但这并没有帮助。我开始使用 2.2.4,但我想我会尝试 2.1.X 火车,因为它已经存在了更长的时间。由于我得到的日志输出,我可以确认正在调用控制器中的正确方法。
尝试替换以下行:
when(vService.findVehicleById(any(),any(),any())).thenReturn(vehicle1);
有了这个(显式提供类any()
(:
when(vService.findVehicleById(any(Long.class),any(Principal.class),any(HttpServletRequest.class))).thenReturn(vehicle1);
忽略以下部分,正如 @M. Deinum 指出的那样,@MockBean
确实注入了模拟对象,因此这无关紧要。
您确实模拟了服务对象,但没有将其注入控制器。
@InjectMocks
private VehicleController vehicleController = new VehicleController();
使用MockitoAnnotations.initMocks(this)
初始化这些模拟对象,而不是自动连接MockMvc
对象尝试像这样传递控制器:
@BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(vehicleController).build();