如何测试在 springboot 集成测试中有效调用 bean 的销毁方法?
How can I test a destroy method of a bean is effectively called in a springboot integration test?
我的配置 class 如下所示:
@SpringBootApplication
public class Application {
@Bean(destroyMethod = "close")
public CassandraClient cassandraClient() { ... }
}
我的 CassandraClient
class 有一个 close()
方法,当应用程序上下文关闭时调用它(我通过步骤调试看到它)。但是,我找不到测试 close()
方法是否被有效调用的方法。
这是我要测试的内容:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ContextConfiguration(classes = { Application.class })
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ApplicationIntegrationTests implements ApplicationContextAware {
ApplicationContext applicationContext;
@Autowired
CassandraClient cassandraClient;
@Test
public void cassandraClientCloseIsCalled() {
((ConfigurableApplicationContext)applicationContext).close();
// How can I check that cassandraClient.close() has been called once ?
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
我尝试在我的配置 class 中添加一个方面来进行计数,但我无法获得匹配 close
方法的切入点。似乎我的方面在 cassandraClient
bean 之前被破坏了。
我看到这个问题已经存在一段时间了,我对此进行了调查并找到了适合我的解决方案。您可以在这里查看:Testing Nuts Example。本质上,杏仁是我使用坚果对象创建的坚果。 init 和 destroy 方法都是私有的,因此我在另一个配置中创建了一个扩展,以便创建一个 mock 并能够使用 Mockito 对其进行验证。这样我就可以隐藏私有方法并为此测试生成 public 方法。但我认为在这种情况下对您来说有趣的是,在我的 @Configuration 中为 @Test 使用 @PreDestroy 注释,然后我可以测试 destroy 方法,只是因为在那个时候,所有的 destroy 方法都被调用了。这是我的代码的副本,只是为了澄清这一点:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {NutsConfiguration.class, NutsMethodsConfigurationTest.NutsTestConfiguration.class})
class NutsMethodsConfigurationTest {
@Autowired
public Nut almond;
@MockBean
public static NutExtended nutExtended;
@Autowired
public ApplicationContext applicationContext;
@Test
void almond() {
ConsolerizerComposer.outSpace()
.orange(almond)
.orange(nutExtended)
.reset();
verify(nutExtended, times(1)).initiate();
}
@Configuration
public static class NutsTestConfiguration {
@Bean
@Primary
@Qualifier("nut")
public NutExtended nut() {
return new NutExtended();
}
@PreDestroy
public void check() {
verify(nutExtended, times(1)).goToCake();
}
}
@Configuration
public static class NutExtended extends Nut {
public void goToCake() {
BROWN.printGenericLn("Going to cake...");
}
public void initiate() {
ORANGE.printGenericLn("Creating %s", toString());
}
}
}
希望对您有所帮助!
我的配置 class 如下所示:
@SpringBootApplication
public class Application {
@Bean(destroyMethod = "close")
public CassandraClient cassandraClient() { ... }
}
我的 CassandraClient
class 有一个 close()
方法,当应用程序上下文关闭时调用它(我通过步骤调试看到它)。但是,我找不到测试 close()
方法是否被有效调用的方法。
这是我要测试的内容:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ContextConfiguration(classes = { Application.class })
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ApplicationIntegrationTests implements ApplicationContextAware {
ApplicationContext applicationContext;
@Autowired
CassandraClient cassandraClient;
@Test
public void cassandraClientCloseIsCalled() {
((ConfigurableApplicationContext)applicationContext).close();
// How can I check that cassandraClient.close() has been called once ?
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
我尝试在我的配置 class 中添加一个方面来进行计数,但我无法获得匹配 close
方法的切入点。似乎我的方面在 cassandraClient
bean 之前被破坏了。
我看到这个问题已经存在一段时间了,我对此进行了调查并找到了适合我的解决方案。您可以在这里查看:Testing Nuts Example。本质上,杏仁是我使用坚果对象创建的坚果。 init 和 destroy 方法都是私有的,因此我在另一个配置中创建了一个扩展,以便创建一个 mock 并能够使用 Mockito 对其进行验证。这样我就可以隐藏私有方法并为此测试生成 public 方法。但我认为在这种情况下对您来说有趣的是,在我的 @Configuration 中为 @Test 使用 @PreDestroy 注释,然后我可以测试 destroy 方法,只是因为在那个时候,所有的 destroy 方法都被调用了。这是我的代码的副本,只是为了澄清这一点:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {NutsConfiguration.class, NutsMethodsConfigurationTest.NutsTestConfiguration.class})
class NutsMethodsConfigurationTest {
@Autowired
public Nut almond;
@MockBean
public static NutExtended nutExtended;
@Autowired
public ApplicationContext applicationContext;
@Test
void almond() {
ConsolerizerComposer.outSpace()
.orange(almond)
.orange(nutExtended)
.reset();
verify(nutExtended, times(1)).initiate();
}
@Configuration
public static class NutsTestConfiguration {
@Bean
@Primary
@Qualifier("nut")
public NutExtended nut() {
return new NutExtended();
}
@PreDestroy
public void check() {
verify(nutExtended, times(1)).goToCake();
}
}
@Configuration
public static class NutExtended extends Nut {
public void goToCake() {
BROWN.printGenericLn("Going to cake...");
}
public void initiate() {
ORANGE.printGenericLn("Creating %s", toString());
}
}
}
希望对您有所帮助!