在 bean 上使用 @PostConstruct 对 @SqlGroup 进行 Spring 测试

Posted

技术标签:

【中文标题】在 bean 上使用 @PostConstruct 对 @SqlGroup 进行 Spring 测试【英文标题】:Spring Test @SqlGroup with @PostConstruct on bean 【发布时间】:2018-08-31 19:49:41 【问题描述】:

在使用 Spring 5、Junit4.11 和 JDK8 运行一些集成测试之前,我正在尝试使用 @SqlGroup 执行一些 SQL 语句。

直到今天,当我在我的“ConfigurationComponent”bean 上添加一些初始配置时,一切都完美无缺,并带有注释 @PostConstruct。

由于@PostConstruct 方法调用依赖于数据库的bean,测试失败,因为hiberante(因此数据库)找不到预加载的模式。

我调查后发现@SqlGroup 中的语句会在ApplicationContext 初始化之后执行,所以@PostConstruct 是在模式加载之前执行的。

这是我的集成测试抽象类。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations =  "classpath:application-context-test.xml" )
@Transactional
@Rollback(true)
@SqlGroup(
        @Sql(executionPhase = ExecutionPhase.BEFORE_TEST_METHOD, scripts = 
                "classpath:db_config.sql",
                "classpath:consultas/setup_esquema_0.1.sql",
                "classpath:db_datos_iniciales.sql"),
        @Sql(executionPhase = ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:db_teardown.sql") )
public abstract class AbstractServiceTest 

    @BeforeClass
    public static void setUpBeforeClass() throws Exception 

    

    @AfterClass
    public static void tearDownAfterClass() throws Exception 
    

    @Before
    public abstract void setUp() throws Exception;

    @After
    public abstract void tearDown() throws Exception;

    public static Long randomId() 
        return new Long(Math.round(Math.random() * 1000));
    


有问题的豆子

@Configuration
public class ConfigurationComponent 

    @Autowired
    Resources resources; // resources are retrieved from database.

    @PostConstruct
    public void startUp() throws VariableGlobalInexistenteException 
        Config.environment = resources
                .getWsaaEnv();
        Config.validation = resources
                .getWsaaEnvValidation();
    


我找不到使用@SqlGroup 解决此问题的方法。是否有任何解决方案,一种改变生命周期并首先执行 sql 语句的方法? 如您所见,我使用的是ExecutionPhase.BEFORE_TEST_METHOD,没有 这种情况下的显式配置,例如“ExecutionPhase.BEFORE_SETUP”。


2018 年 9 月 7 日更新 - 似乎无法使用 @Sql 实现此目的:

@Sql 和 @PostConstruct 的调用都由 Spring 处理 框架而不是 Spring Boot。另外,我相信这是 设计的。 @Sql 的默认执行阶段是 BEFORE_TEST_METHOD (另一个选项是 AFTER_TEST_METHOD)。应用程序上下文是 刷新,因此整个调用一次 @PostConstruct 测试类(事实上,如果它们可能是多个测试类一次 共享相同的配置)发生在单独测试之前 方法被调用。换句话说,您不能使用 @Sql 作为 为 @PostConstruct 中的调用准备数据库。

Github @PostConstruct executed before @Sql

【问题讨论】:

【参考方案1】:

我设法找到了解决方法。正如最新更新所述,使用@SqlGroup 无法实现所需的行为。我不得不使用以下方法,使用@BeforeClass 和@AfterClass:

@BeforeClass
public static void setUpBeforeClass() throws Exception 

    DriverManagerDataSource dataSource = getDataSource();
    Connection conn = dataSource.getConnection();
    ScriptUtils.executeSqlScript(conn, new ClassPathResource("db_config.sql"));
    ScriptUtils.executeSqlScript(conn, new ClassPathResource("consultas/setup_schema"));
    ScriptUtils.executeSqlScript(conn, new ClassPathResource("db_init.sql"));
    JdbcUtils.closeConnection(conn);



@AfterClass
public static void tearDownAfterClass() throws Exception 
    Connection conn = getDataSource().getConnection();
    ScriptUtils.executeSqlScript(conn, new ClassPathResource(
            "db_teardown.sql"));
    JdbcUtils.closeConnection(conn);


private static DriverManagerDataSource getDataSource() 
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl(url);
    dataSource.setUsername(username);
    dataSource.setPassword(password);
    dataSource.setDriverClassName(driver);
    return dataSource;

所有@SqlGroup 注释已被删除。这种方法非常简洁,因为 ScriptUtils 不需要太多的依赖项即可运行。

【讨论】:

【参考方案2】:

另一种解决方法是实现 CommandLineRunner。

@Component
public class ConfigurationInitRunner implements CommandLineRunner 

    @Autowired
    Resources resources; // resources are retrieved from database.

    @Override
    public void run(String... strings) throws Exception 
        Config.environment = resources.getWsaaEnv();
        Config.validation = resources.getWsaaEnvValidation();
    

【讨论】:

以上是关于在 bean 上使用 @PostConstruct 对 @SqlGroup 进行 Spring 测试的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用@PostConstruct?

踩坑:@PostConstruct@DependsOn@Order注解嵌套使用解决Bean加载优先级问题

踩坑:@PostConstruct@DependsOn@Order注解嵌套使用解决Bean加载优先级问题

有条件的@PostConstruct 注解

哪个先执行:@PostConstruct和@Bean的initMethod?

JSF bean:设置 ViewParam 后调用 @PostConstruct 函数