我正在处理我的第一个 Spring Boot 应用程序,我发现在尝试使用 JUnit 测试我的控制器类时遇到了一些困难。
所以我有以下情况,这是我的控制器类名为 PlaceSearcherController :
@RestController
@RequestMapping("/PlaceSearcher")
public class PlaceSearcherController {
private static final Logger log = LoggerFactory.getLogger(PlaceSearcherController.class);
@Autowired
private MainSearchServices mainSearchServices;
@RequestMapping(value = "hello")
public String hello() {
return "Hello World";
}
@RequestMapping(value = "",
method = RequestMethod.GET)
public ResponseEntity<String> home() {
List<AccomodationDTO> accomodationDTOs = new ArrayList<>();
return ResponseEntity.ok("c è figa");
}
@RequestMapping(value = "getBestListHotel",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<AccomodationDTO>> getHolteListFromPlace(@Valid @RequestBody MainSearchListHotelVO searchObject) {
List<AccomodationDTO> accomodationDTOs = new ArrayList<>();
log.debug("search vo in input: " + searchObject);
try {
accomodationDTOs = mainSearchServices.getBestHotelListFromPlace(searchObject);
} catch (Exception e) {
log.error("Exception: ", e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
if (accomodationDTOs.isEmpty()) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
}
return ResponseEntity.ok(accomodationDTOs);
}
@RequestMapping(value = "getHotelById",
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<AccomodationDTO> getHoltelById( Integer id ) {
AccomodationDTO accomodationDTO = null;
try {
accomodationDTO = mainSearchServices.getHotelFromId(id);
} catch (Exception e) {
log.error("Exception: ", e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
if ( accomodationDTO==null ) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
}
return ResponseEntity.ok(accomodationDTO);
}
@RequestMapping(value = "getListRoomByHotelId",
method = RequestMethod.GET,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<RoomDTO>> getListRoomByHotelId( Integer hotelId ) {
List<RoomDTO> roomDTOs = null;
try {
roomDTOs = mainSearchServices.getListRoomByHotelId(hotelId);
} catch (Exception e) {
log.error("Exception: ", e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
}
if ( roomDTOs==null ) {
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(null);
}
return ResponseEntity.ok(roomDTOs);
}
}
然后我有一个名为 PlaceSearcherControllerTest 的 JUnit 测试类,其中包含以下代码:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PlaceSearcherControllerTest {
@Autowired
private PlaceSearcherController placeSearcherController;
@Test
public void placeSearcherControllerTest() {
System.out.println("placeSearcherControllerTest START");
System.out.println("placeSearcherControllerTest END");
}
}
此时 placeSearcherControllerTest()方法什么都不做,我只是尝试运行定义到JUnit类中的JUnit测试方法,该类获取 PlaceSearcherController 控制器实例。
所以问题是运行以前的 placeSearcherControllerTest()测试方法我得到以下错误信息:
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
at org.springframework.util.Assert.state(Assert.java:392)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.getOrFindConfigurationClasses(SpringBootTestContextBootstrapper.java:173)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.processMergedContextConfiguration(SpringBootTestContextBootstrapper.java:133)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:409)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildDefaultMergedContextConfiguration(AbstractTestContextBootstrapper.java:323)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:277)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:112)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:78)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:120)
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:105)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTestContextManager(SpringJUnit4ClassRunner.java:152)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.<init>(SpringJUnit4ClassRunner.java:143)
at org.springframework.test.context.junit4.SpringRunner.<init>(SpringRunner.java:49)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:36)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:96)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Process finished with exit code -1
为什么呢?怎么了?我错过了什么?如何解决此问题并正确获取 PlaceSearcherController 实例到我的JUnit测试类中?
错误消息告诉我:无法找到@SpringBootConfiguration,您需要在测试中使用@ContextConfiguration或@SpringBootTest(classes = ...)
这些 @SpringBootConfiguration , @ContextConfiguration 和 @SpringBootTest 是什么?
在这里阅读:http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/SpringBootConfiguration.html在我看来, @SpringBootConfiguration 可用于提供bean定义(作为Spring中的 @Configuration 类而不是使用Spring Boot)。
我的测试类使用 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)进行注释,并在此处阅读:http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html它说:
Spring Boot提供@SpringBootTest注释,可以用作 标准spring-test @ContextConfiguration的替代品 需要Spring Boot功能时的注释。注释的工作原理 通过创建测试中使用的ApplicationContext SpringApplication
所以我认为我有应用程序上下文从哪里获取我的控制器实例。我不知道如何解决它。我认为我缺少一些东西,解决方案必须非常简单,因为我只有一个控制器类和测试类。你能帮我告诉我怎样才能解决?
TNX
答案 0 :(得分:2)
假设您的控制器位于com.example.foo.controller
,并且您的测试位于同一目录中。我们现在假设您的主要班级(@SpringBootApplication
)位于com.example.foo.app
。您可能已经调整了组件扫描指令,因为您有一个不寻常的设置。
这对测试也有影响!测试支持将尝试通过查找父包来查找@SpringBootConfiguration
(@SpringBootApplication
是@SpringBootConfiguration
)以查找匹配项。如果不是,它将抛出此异常。
搜索算法从包含测试的包开始工作,直到找到@SpringBootApplication或@SpringBootConfiguration注释类。只要您以合理的方式构建代码,通常就可以找到主要配置。
因此,它会在com.example.foo.controller
,然后com.example.foo
然后com.example
然后com
中搜索此类匹配。最终它放弃并抛出异常。
您尚未在@SpringBootTest
中提供上下文,因此无法了解要启动的上下文。尝试在其中添加对@SpringBootApplication
的引用,例如:
@SpringBootTest(classes = MyApp.class, webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
如果我的假设是正确的,我强烈建议您检查一下您的包装结构。