无法使用@SpringBootTest 执行控制器测试
Can not execute controller test with @SpringBootTest
我有一个 Spring 启动应用程序。版本是 2.3.1
.
主应用程序如下所示:
@AllArgsConstructor
@SpringBootApplication
public class LocalServiceApplication implements CommandLineRunner {
private final DataService dataService;
private final QrReaderServer qrReaderServer;
private final MonitoringService monitoringService;
@Override
public void run(String... args) {
dataService.fetchData();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
public static void main(String[] args) {
SpringApplication.run(LocalServiceApplication.class, args);
}
}
应用程序启动后,我必须执行 3 个不同的步骤,这些步骤已完成 CommandLineRunner
:
- 首先获取远程数据并将其存储在本地(测试配置文件跳过此步骤)
- 使用 WatchService.
启动文件上传的异步文件夹监控
- 启动 TCP 服务器
我有一个这样的控制器:
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/v1/permissions")
public class CarParkController {
private final PermissionService permissionService;
@PostMapping
public CarParkPermission createPermission(@RequestBody @Valid CarParkPermission permission) {
return permissionService.createPermission(permission);
}
}
使用 Junit 5 的 Ant 测试如下:
@ActiveProfiles("test")
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class CarParkControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private PermissionService permissionService;
private final Gson gson = new Gson();
@Test
void testCreatingNewPermissionSuccess() throws Exception {
CarParkPermission permission = CarParkPermission.builder()
.id(56)
.permissionCode("1234")
.build();
when(permissionService.createPermission(refEq(permission))).thenReturn(permission);
postPermission(permission).andExpect(status().isOk());
}
private <T> ResultActions postPermission(T instance) throws Exception {
return this.mockMvc.perform(post("/v1/permissions")
.contentType(MediaType.APPLICATION_JSON)
.content(gson.toJson(instance)));
}
}
看起来应该可以正常工作。
然而,测试没有执行:
2020-08-27 14:42:30.308 INFO 21800 --- [ main] c.s.i.CarParkControllerIntegrationTest : Started CarParkControllerIntegrationTest in 8.593 seconds (JVM running for 10.03)
2020-08-27 14:42:30.334 INFO 21800 --- [ main] c.s.s.s.DataServiceTestImpl : Fetch data for test profile is skipped
2020-08-27 14:42:30.336 DEBUG 21800 --- [ carpark-ex-1] c.s.monitoring.MonitoringServiceImpl : START_MONITORING Results from Cameras for folder: D:\results-from-camera
2020-08-27 14:42:30.751 DEBUG 21800 --- [ main] c.s.netty.TCPServer : TCP Server is STARTED : port 9090
在这些行之后执行永远挂起。
更新
监控任务详情如下:
@Async
@Override
public void launchMonitoring() {
log.debug("START_MONITORING Results from Cameras for folder: {}", properties.getFolder());
try {
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == ENTRY_CREATE) {
log.info("FILE_CREATED: {}", event.context());
// processing resource
deleteResource(zipFullPath);
} else if (kind == ENTRY_DELETE) {
log.info("RESOURCE_DELETED: {}", event.context());
}
}
key.reset();
}
} catch (InterruptedException e) {
log.error("interrupted exception for monitoring service", e);
Thread.currentThread().interrupt();
}
}
另外AsyncConfiguration
配置了TaskExecutor
从 TCPServer 启动的方法看起来:
@Override
public void launchServer() {
try {
ChannelFuture serverChannelFuture = serverBootstrap.bind(hostAddress).sync();
log.debug("TCP Server is STARTED : port {}", hostAddress.getPort());
serverChannel = serverChannelFuture.channel().closeFuture().sync().channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
shutdownQuietly();
}
}
如何解决这个问题?
已了解执行被阻止(感谢 M.Deinum)。
因此更改了最后一个方法:
@Async
@Override
public void launchServer() {
// ...
}
并转移到 ObjectMapper
而不是 Gson
以将实例转换为 JSON 格式:
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class CarParkControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper mapper;
@Test
void testCreatingNewPermissionSuccess() throws Exception {
CarParkPermission permission = CarParkPermission.builder()
.id(444)
.permissionCode("1234")
.build();
postPermission(permission).andExpect(status().isOk());
}
private <T> ResultActions postPermission(T instance) throws Exception {
return this.mockMvc.perform(post("/v1/permissions")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(instance)));
}
}
最后,一切正常。
我有一个 Spring 启动应用程序。版本是 2.3.1
.
主应用程序如下所示:
@AllArgsConstructor
@SpringBootApplication
public class LocalServiceApplication implements CommandLineRunner {
private final DataService dataService;
private final QrReaderServer qrReaderServer;
private final MonitoringService monitoringService;
@Override
public void run(String... args) {
dataService.fetchData();
monitoringService.launchMonitoring();
qrReaderServer.launchServer();
}
public static void main(String[] args) {
SpringApplication.run(LocalServiceApplication.class, args);
}
}
应用程序启动后,我必须执行 3 个不同的步骤,这些步骤已完成 CommandLineRunner
:
- 首先获取远程数据并将其存储在本地(测试配置文件跳过此步骤)
- 使用 WatchService. 启动文件上传的异步文件夹监控
- 启动 TCP 服务器
我有一个这样的控制器:
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/v1/permissions")
public class CarParkController {
private final PermissionService permissionService;
@PostMapping
public CarParkPermission createPermission(@RequestBody @Valid CarParkPermission permission) {
return permissionService.createPermission(permission);
}
}
使用 Junit 5 的 Ant 测试如下:
@ActiveProfiles("test")
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class CarParkControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private PermissionService permissionService;
private final Gson gson = new Gson();
@Test
void testCreatingNewPermissionSuccess() throws Exception {
CarParkPermission permission = CarParkPermission.builder()
.id(56)
.permissionCode("1234")
.build();
when(permissionService.createPermission(refEq(permission))).thenReturn(permission);
postPermission(permission).andExpect(status().isOk());
}
private <T> ResultActions postPermission(T instance) throws Exception {
return this.mockMvc.perform(post("/v1/permissions")
.contentType(MediaType.APPLICATION_JSON)
.content(gson.toJson(instance)));
}
}
看起来应该可以正常工作。
然而,测试没有执行:
2020-08-27 14:42:30.308 INFO 21800 --- [ main] c.s.i.CarParkControllerIntegrationTest : Started CarParkControllerIntegrationTest in 8.593 seconds (JVM running for 10.03)
2020-08-27 14:42:30.334 INFO 21800 --- [ main] c.s.s.s.DataServiceTestImpl : Fetch data for test profile is skipped
2020-08-27 14:42:30.336 DEBUG 21800 --- [ carpark-ex-1] c.s.monitoring.MonitoringServiceImpl : START_MONITORING Results from Cameras for folder: D:\results-from-camera
2020-08-27 14:42:30.751 DEBUG 21800 --- [ main] c.s.netty.TCPServer : TCP Server is STARTED : port 9090
在这些行之后执行永远挂起。
更新
监控任务详情如下:
@Async
@Override
public void launchMonitoring() {
log.debug("START_MONITORING Results from Cameras for folder: {}", properties.getFolder());
try {
WatchKey key;
while ((key = watchService.take()) != null) {
for (WatchEvent<?> event : key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == ENTRY_CREATE) {
log.info("FILE_CREATED: {}", event.context());
// processing resource
deleteResource(zipFullPath);
} else if (kind == ENTRY_DELETE) {
log.info("RESOURCE_DELETED: {}", event.context());
}
}
key.reset();
}
} catch (InterruptedException e) {
log.error("interrupted exception for monitoring service", e);
Thread.currentThread().interrupt();
}
}
另外AsyncConfiguration
配置了TaskExecutor
从 TCPServer 启动的方法看起来:
@Override
public void launchServer() {
try {
ChannelFuture serverChannelFuture = serverBootstrap.bind(hostAddress).sync();
log.debug("TCP Server is STARTED : port {}", hostAddress.getPort());
serverChannel = serverChannelFuture.channel().closeFuture().sync().channel();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
shutdownQuietly();
}
}
如何解决这个问题?
已了解执行被阻止(感谢 M.Deinum)。
因此更改了最后一个方法:
@Async
@Override
public void launchServer() {
// ...
}
并转移到 ObjectMapper
而不是 Gson
以将实例转换为 JSON 格式:
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class CarParkControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper mapper;
@Test
void testCreatingNewPermissionSuccess() throws Exception {
CarParkPermission permission = CarParkPermission.builder()
.id(444)
.permissionCode("1234")
.build();
postPermission(permission).andExpect(status().isOk());
}
private <T> ResultActions postPermission(T instance) throws Exception {
return this.mockMvc.perform(post("/v1/permissions")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(instance)));
}
}
最后,一切正常。