使用注释在Spring junit测试中注入sql数据

时间:2010-07-16 08:12:58

标签: junit

我使用Junit进行spring-test,我希望通过这个注释进行经典的事务测试:

@Injectdata("classpath:src/test/mydata.sql")
@Test
public void myTest throws Exception {
    // ...
}

此数据将在同一事务中使用jdbcspring模板注入。这些数据将可用 只有这个测试。

实际上,我以这种方式注入数据:

@Test
public void myTest throws Exception {
    jdbcTemplate.update("my sql query);
}

我知道Unitils框架使用数据集dbunit文件做同样的事情。

2 个答案:

答案 0 :(得分:3)

我自己创建了一个解决方案。

首先创建Spring测试使用的监听器:

public class InjectDataTestExecutionListener extends DependencyInjectionTestExecutionListener {

    private static JdbcTemplate jdbcTemplate;
    private static  DataSource datasource ;
    private static String ENCODING="UTF-8";


    @Override
    /**
     * Execute un éventuel script SQL indiqué via l'annotation  {@link SqlFileLocation} 
     * avant l'execution d'un test.
     */
    public void beforeTestMethod(TestContext testContext) throws Exception {
        super.beforeTestClass(testContext);

       Method MyMethdo = testContext.getTestMethod();
       SqlFileLocation dsLocation = MyMethdo.getAnnotation(SqlFileLocation.class);
        if (dsLocation!=null){
            executeSqlScript(testContext,dsLocation.value());
        }
    }

    /**
     * Execute un script sur un chemin d'accès au fichier.
     * @param testContext le context du test
     * @param sqlResourcePath le chemin du fichier Sql
     * @throws DataAccessException en cas d'erreur d'accès au fichier
     */
    private  void executeSqlScript(TestContext testContext, String sqlResourcePath) throws DataAccessException {
      JdbcTemplate jdbcTemplate = getJdbCTemplate(getDatasource(testContext));
      Resource resource = testContext.getApplicationContext().getResource(sqlResourcePath);
      executeSqlScript(jdbcTemplate, new EncodedResource(resource,ENCODING));
    }

    private DataSource getDatasource(TestContext testContext) {
        if (datasource==null){
            datasource = testContext.getApplicationContext().getBean(DataSource.class);
        }  
        return datasource;
    }

    private JdbcTemplate getJdbCTemplate(DataSource datasource) {
        if (jdbcTemplate==null){
            jdbcTemplate = new JdbcTemplate(datasource);
        }  
        return jdbcTemplate;
    }

    /**
     * Execute une resource via un jdbcTemplate donné.
     * @throws DataAccessException enc as de pb d'acces au fichier.
     */
    private static void executeSqlScript(JdbcTemplate simpleJdbcTemplate,
            EncodedResource resource) throws DataAccessException {

        List<String> statements = new LinkedList<String>();
        try {
            LineNumberReader lnr = new LineNumberReader(resource.getReader());
            String script = JdbcTestUtils.readScript(lnr);
            char delimiter = ';';
            if (!JdbcTestUtils.containsSqlScriptDelimiters(script, delimiter)) {
                delimiter = '\n';           
            }
            JdbcTestUtils.splitSqlScript(script, delimiter, statements);
            for (String statement : statements) {
                try {
                    simpleJdbcTemplate.update(statement);
                }
                catch (DataAccessException ex) {
                        throw ex;
                }
            }
        }
        catch (IOException ex) {
            throw new DataAccessResourceFailureException("Impossible d'ouvrir le script depuis " + resource, ex);
        }
    }
}

比你的班级测试添加:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={/* ... */})
@Transactionnal
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,DirtiesContextTestExecutionListener.class,TransactionalTestExecutionListener.class
    ,InjectDataTestExecutionListener.class    
})

TRICK 是添加通常由Spring自动添加的所有侦听器,如果您不添加侦听器。避免这会导致奇怪的错误。

这没有记录,但是我发现如果没有带有transactionnal spring测试的监听器,Spring会自动添加这3个监听器(感谢调试模式!)

最后,你给我们这个很酷的注释:

@SqlFileLocation("classpath:sql/myfil.sql")
@Test
public void testGetAll() throws Exception {/*...*/}

您甚至可以使用相对路径或绝对路径。

自然插入将像其他插入一样自动回滚。

答案 1 :(得分:0)

也许@Sql注释可以做得更好。