避免在 Spring Boot @WebMvcTest 测试中扩散 @MockBeans

Avoid proliferation of @MockBeans in Spring Boot @WebMvcTest test

我有一个简单的控制器,例如

@Controller
public class FooController
{
    @Autowired
    private BarService barService;

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public String displayFoo()
    {
        return "foo";
    }
}

当我想做 @WebMvcTest 时,我必须创建大量 @MockBeans 以防止 NoSuchBeanDefinitionException

@RunWith(SpringRunner.class)
@WebMvcTest
@Import(WebSecurityConfig.class)
public class FooControllerTest
{
    @MockBean ...
    @MockBean ...
    @MockBean ...
    ...
    ...
}

这是否意味着 BarService 以某种方式创建了一个依赖链? (它有一些依赖性,但有些 @MockBean 看起来完全不相关)。

问题是,我为不同的控制器添加的每个 @WebMvcTest 也需要相同的 @MockBean

我是否应该使用像 @TestConfiguration 这样的注释来指定 DRY 主体的所有 @MockBean

我又看了一遍,发现您可以将控制器名称传递给 @WebMvcTest 例如@WebMvcTest(FooController.class).

Specifies the controllers to test. May be left blank if all {@code @Controller} beans should be added to the application context.

正如Hal8k所说,如果你没有像@WebMvcTest(YourController.class)那样指定控制器,它会尝试加载所有@Controller组件。并且 @Import(WebSecurityConfig.class) 也尝试在 WebSecurityConfig.class 中注入组件。

参考:https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4

当 bean 扫描配置错误或过多时,可能会发生这种情况。

就我而言,尽管在 @WebMvcTest(FooController.class) 中指定了要测试的控制器,但我仍然遇到错误。

我最终意识到这是因为我的应用程序 @ComponentScan 被不必要地弄乱了。我的 Application.java 是这样的:

@SpringBootApplication
@ComponentScan({"fr.nevechris.projectname","fr.nevechris.projectname.otherpackage"})
public class Application {

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

我完全删除了 @ComponentScan,问题就解决了。

如果您的 @ComponentScan 很好或未指定,请尝试在您的项目中搜索已完成配置的其他位置(例如 @Configuration 标记)。