Spring 引导@SpyBean导致测试套件出错,可能是由于上下文未重置的问题



我在弹簧集成测试中遇到了问题。

行为:

  • 当我单独运行下面的测试时,它是成功的。

  • 但是,当运行所有测试时,包括下面的测试在内的许多测试都是错误的。

  • 当我忽略下面的测试并运行所有测试时,所有测试都成功了。

我没有包含错误堆栈跟踪,因为它与我们的业务逻辑高度相关,我怀疑该错误与我对 Spring 启动测试@SpyBean的使用有关。

这是测试:

@RunWith(SpringRunner.class)
@ActiveProfiles(profiles = "test")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
...
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private DataKeyStore dataKeyStore;
@SpyBean
private TokenTools tokenTools;
...
@Test
public void myTest() throws Exception {
doReturn("someGeneratedToken")
.doReturn("someGeneratedToken")
.doCallRealMethod()
.when(tokenTools)
.createToken(any(TokenProfile.class), anyString(), anyString());
...

请注意,DataKeyStoreTokenTools的依赖关系。

正如我上面所说,我怀疑测试正在相互踩踏,我的@SpyBean不知何故泄漏到其他测试类上......

我的问题是我如何确保此测试不会踩到其他测试?我已经尝试了@DirtiesContext注释无济于事...

同样让我感到困惑的是,@SpyBean已经被重置(根据文档/javadoc)。

谁能帮忙?

编辑:使用我的 IDE 调试测试表明TokenTools对所有测试仅实例化两次:一次在测试初始化时,第二次用于为上述测试创建@SpyBean。在上述测试之后运行的其余测试使用第二个实例,即@SpyBean实例...

我最近遇到了同样的问题。确保为您的类模式设置正确的类模式@DirtiesContext注释。

默认情况下,@DirtiesContext将在完成测试类后重置@SpyBean。您可能希望在每个测试方法之前或之后重置它。

因此,请将@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)添加到您的测试类中。

我可以确认@DirtiesContext对我们不起作用。在旧上下文关闭(通过@DirtiesContext注释)后,我们在为新上下文初始化数据库(使用 Liquibase)时遇到了问题。

我们最终为伪造一些本斯的测试以不同的方式命名 Spring 测试上下文:

例如:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = SpringBootApp.class, name = "mainContext")
public class TestThatDoesntFakeBeans(){
}
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = SpringBootApp.class, name = "contextWithFakeBean")
public class TestThatFakeBeans(){
@SpyBean
//...
}

这样,就可以为每个名称创建单独的 Spring 上下文。具有相同名称的上下文由测试重用。但是,当然,您需要确保具有相同上下文名称的测试不会相互影响。

>@SpyBean似乎在每次测试后都不会重置,从而导致异常行为。我建议改用Mockito@Spy,并检查问题是否仍然存在。

import org.mockito.Spy
....
@RunWith(SpringRunner.class)
@ActiveProfiles(profiles = "test")
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
...
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private DataKeyStore dataKeyStore;
@Spy
private TokenTools tokenTools;
...
@Test
public void myTest() throws Exception {
doReturn("someGeneratedToken")
.doReturn("someGeneratedToken")
.doCallRealMethod()
.when(tokenTools)
.createToken(any(TokenProfile.class), anyString(), anyString());
...

最新更新