为什么我不能将控制器实例自动装入这个Spring Boot应用程序的JUnit类?无法找到@SpringBootConfiguration

时间:2016-10-26 10:58:27

标签: spring junit spring-boot

我正在处理我的第一个 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

1 个答案:

答案 0 :(得分:2)

假设您的控制器位于com.example.foo.controller,并且您的测试位于同一目录中。我们现在假设您的主要班级(@SpringBootApplication)位于com.example.foo.app。您可能已经调整了组件扫描指令,因为您有一个不寻常的设置。

这对测试也有影响!测试支持将尝试通过查找父包来查找@SpringBootConfiguration@SpringBootApplication@SpringBootConfiguration)以查找匹配项。如果不是,它将抛出此异常。

关键是this section of the doc

  

搜索算法从包含测试的包开始工作,直到找到@SpringBootApplication或@SpringBootConfiguration注释类。只要您以合理的方式构建代码,通常就可以找到主要配置。

因此,它会在com.example.foo.controller,然后com.example.foo然后com.example然后com中搜索此类匹配。最终它放弃并抛出异常。

您尚未在@SpringBootTest中提供上下文,因此无法了解要启动的上下文。尝试在其中添加对@SpringBootApplication的引用,例如:

@SpringBootTest(classes = MyApp.class, webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)

如果我的假设是正确的,我强烈建议您检查一下您的包装结构。