19

我在 Spring Framework 上运行了几个集成测试,这些测试扩展了名为BaseITCase的基类。
像这样:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppCacheConfiguration.class, TestConfiguration.class}, loader = SpringBootContextLoader.class)
@Transactional
@WebMvcTest
public abstract class BaseITCase{...}
...
public class UserControllerTest extends BaseITCase {...}

问题是其中一个测试有几个声明: @MockBean 在其中,并且在执行该测试的那一刻,Spring 重新创建上下文,并且此测试之后的测试有时会使用错误的 bean(来自使用 @ 完全为测试创建的上下文模拟豆)。我只是通过检查 bean 具有不同的哈希码才发现这一点。

当我使用@EventListener 时,它变得非常重要。因为调用了错误上下文(已经完成执行的测试类的上下文)的侦听器,并且我在那里有错误的 bean。

有什么解决方法吗?

我尝试将所有 @MockBean 声明移至基本类,它工作正常,因为没有创建新的上下文。但是,它使基础课太重了。另外,我试图为这个测试创建一个脏上下文,但是下一个测试失败并显示上下文已经关闭的消息。

4

2 回答 2

21

原因是带有@MockBean 的测试的spring 配置与其他测试不同,所以spring 框架无法缓存以前使用的上下文,需要重新加载。在这里可以找到更详细的解释:https ://github.com/spring-projects/spring-boot/issues/10015

正如您所说,如果您将模拟 bean 移动到父类,则不会重新加载上下文,这是有道理的,因为 bean 配置保持不变。

一种可能的解决方法是将您的模拟 bean 定义为一个简单的模拟,并在需要的地方手动注入它。

例如,UserController依赖于Foo

public class UserControllerTest extends BaseITCase {

    private Foo foo = Mockito.mock(Foo.class);

    @Autowired
    private UserController userController;

    @Before
    public void setUp() {
        super.setup();

        this.userController.setFoo(foo);
    }
}

@Component
public class UserController {

    private Foo foo;

    @Autowired
    public void setFoo(final Foo foo) {
        this.foo = foo;
    }
}

希望这可以帮助。

于 2018-02-26T11:57:14.683 回答
2

@MockBean可能会导致上下文重新加载,如上一个答案中所述

作为替代方案,如果您使用的是 spring boot 2.2+,您可以使用@MockInBean而不是@MockBean. 它使您的上下文保持干净,并且不需要重新加载您的上下文。

@SpringBootTest
public class UserControllerTest extends BaseITCase {

    @MockInBean(UserController.class)
    private Foo foo;

    @Autowired
    private UserController userController;

    @Test
    public void test() {
        userController.doSomething();
        Mockito.verify(foo).hasDoneSomething();
    }
}

@Component
public class UserController {

    @Autowired
    private Foo foo;

}

免责声明:我为此确切目的创建了这个库:在 spring bean 中模拟 bean 并避免冗长的上下文重新创建。

于 2021-03-18T00:35:05.827 回答