【问题标题】:How to exclude other @Controller from my context when testing using Spring Boot @WebMvcTest使用 Spring Boot @WebMvcTest 进行测试时如何从我的上下文中排除其他 @Controller
【发布时间】:2018-03-09 15:57:56
【问题描述】:

我有多个控制器,我的理解是,通过在 @WebMvcTest 中指定一个控制器,其他控制器不会被加载到上下文中。来自docs

controllers - 指定要测试的控制器。如果应将所有 @Controller bean 添加到应用程序上下文中,则可以留空。

我的第一个控制器

@Controller
public class MyController {

    @Autowired
    private MyService myService;

    private final Logger logger = Logger.getLogger(this.getClass());

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public @ResponseBody ResponseEntity<String> index() {
        try {
            myService.get();
            return new ResponseEntity<String>(HttpStatus.OK);
        } catch (Exception e) {
            logger.error(e);
            e.printStackTrace();
        }
        return new ResponseEntity<String>("REQUEST FAILED", HttpStatus.INTERNAL_SERVER_ERROR);
    }

}

我的另一个控制器

@Controller
public class MyOtherController {

    @Autowired
    private MyOtherService myOtherService;

    etc...
}

我的控制器测试

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = { MyController.class }, secure = false)
@ActiveProfiles({ "test" })
public class MyControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    MyService myService;

    @Test
    public void testBaseReq() throws Exception {
        Testing dummyData = new Testing();
        dummyData.setData("testing");
        when(myService.get(anyInt())).thenReturn(dummyData);

        this.mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk());
    }
}

但是当我运行这个测试时,它在加载上下文时尝试从 MyOtherContoller 加载 bean MyOtherService 失败。

2017-09-28 11:50:11.687 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'myOtherController'
2017-09-28 11:50:11.687 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating instance of bean 'myOtherController'
2017-09-28 11:50:11.687 DEBUG 16552 --- [           main] o.s.b.f.annotation.InjectionMetadata     : Registered injected element on class [my.package.other.myOtherController]: AutowiredFieldElement for private my.package.other.myOtherService my.package.other.myOtherController.myOtherService
2017-09-28 11:50:11.687 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Eagerly caching bean 'myOtherController' to allow for resolving potential circular references
2017-09-28 11:50:11.687 DEBUG 16552 --- [           main] o.s.b.f.annotation.InjectionMetadata     : Processing injected element of bean 'myOtherController': AutowiredFieldElement for private my.package.other.myOtherService my.package.other.myOtherController.myOtherService
2017-09-28 11:50:11.688 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'myOtherService'
2017-09-28 11:50:11.688 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating instance of bean 'myOtherService'
2017-09-28 11:50:11.689 DEBUG 16552 --- [           main] o.s.b.f.annotation.InjectionMetadata     : Registered injected element on class [my.package.other.myOtherService]: AutowiredFieldElement for private my.package.other.myOtherMapper my.package.other.myOtherService.myOtherMapper
2017-09-28 11:50:11.689 DEBUG 16552 --- [           main] o.s.b.f.annotation.InjectionMetadata     : Registered injected element on class [my.package.other.myOtherService]: AutowiredFieldElement for private ie.aib.services.coredemo.FinancialsRegionService my.package.other.myOtherService.financialsRegionService
2017-09-28 11:50:11.689 DEBUG 16552 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Eagerly caching bean 'myOtherService' to allow for resolving potential circular references
2017-09-28 11:50:11.689 DEBUG 16552 --- [           main] o.s.b.f.annotation.InjectionMetadata     : Processing injected element of bean 'myOtherService': AutowiredFieldElement for private my.package.other.myOtherMapper my.package.other.myOtherService.myOtherMapper
2017-09-28 11:50:11.690  WARN 16552 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myOtherController': Unsatisfied dependency expressed through field 'myOtherService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myOtherService': Unsatisfied dependency expressed through field 'myOtherMapper'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'my.package.other.myOtherMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我认为在 WebMvcTest 注释中指定要测试的控制器会将其限制为仅加载该控制器。但是它试图加载另一个控制器并且因为它的 bean 没有被模拟它失败了。

我遗漏了什么或者我的理解不正确?我想我应该只需要为被测控制器模拟 bean。我还尝试了 excludeFilter 来专门排除另一个 Controller 的包,但这并没有改变错误。

【问题讨论】:

  • 您的应用程序类是什么样的?

标签: java spring unit-testing spring-boot junit


【解决方案1】:

请确保 Application.class 您的测试选择,不包含 @ComponentScan 注释。例如,这是你的包结构

abc-project
  +--pom.xml
  +--src
    +-- main
      +-- com
        +-- abc
          +-- Application.java
          +-- controller
            +-- MyController.java
    +-- test
      +-- com
        +-- abc
          +-- Application.java
          +-- controller
            +-- MyControllerTest.java

test下的Application.java应该和这个例子类似,

@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

【讨论】:

  • 谢谢@Indra,我认为这是我的问题。我有一个 \@ComponentScan,因为我需要显式过滤以排除包含的 jar 中的某些组件。我现在正在寻找改变它,所以在运行 WebMvcTests 时我有一个单独的 Application 类
  • 谢谢,你让我开心。我遇到了一个不同的错误(Spring 试图实例化一个埋在上下文中的 bean,不应该在测试中实例化),你的建议也对我有用。
  • 我遇到了同样的问题,但不幸的是,这个解决方案对我不起作用。 @SpringBootApplication 注释带有 @ComponentScan 如果我删除 @ComponentScan 每个测试开始给出 404
  • @IvanVilanculo 如果不了解您的项目结构,我很难发表评论
【解决方案2】:

my.package.other.myOtherMapper(可能是 Mybatis Mapper 文件)丢失或未明确初始化。

据我了解,myOtherService 实现类有未正确映射的 Mapper 文件。

您可能必须先映射它们。如果可能,您可以发布 Mapper xml 内容。

  <context:component-scan base-package="org.example">       
    <context:exclude-filter type="custom" expression="abc.xyz.MyOtherController"/>
  </context:component-scan>

【讨论】:

  • 是的 myOtherMapper 没有初始化,但它试图实例化它,因为它试图将 MyOtherController 加载到上下文中。如果该控制器被排除在上下文之外,我认为它应该是,那么 myOtherService 将不会被查找,因此 myOtherMapper 也不会被查找。
  • 我可以通过在 MyOtherService 的测试中添加 @MockBean 来绕过它,但我不应该模拟每个服务来测试只使用一个服务的控制器。
  • 谢谢,但我已经尝试了一个排除过滤器来忽略另一个控制器的包,没有任何区别
  • stackoverflow.com/questions/13034515/… 您可以根据此答案排除特定类。您可能在其他方面有问题
猜你喜欢
  • 2017-05-21
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 2018-08-29
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 1970-01-01
相关资源
最近更新 更多