JUnit + Derby + Spring:每次测试后都会丢弃内存数据库

时间:2011-01-17 21:05:00

标签: java spring junit derby in-memory-database

在我的单元测试中,我自动安装了一些使用

等URL的DataSource
jdbc:derby:memory:mydb;create=true

创建内存中的数据库。

要删除内存Derby数据库,您必须连接:

jdbc:derby:memory:mydb;drop=true

我希望在每次测试后都能发生这种情况,并从一个新的数据库开始。我怎么能用Spring做到这一点?

6 个答案:

答案 0 :(得分:5)

如果将Spring与Hibernate一起使用,有一种与数据库无关的方法。

确保在每个测试方法之前/之后创建/销毁应用程序上下文:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:application-context-test.xml"})
@TestExecutionListeners({DirtiesContextTestExecutionListener.class, 
    DependencyInjectionTestExecutionListener.class})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class AbstractTest {

}

指示Hibernate在启动时自动创建架构并在关闭时删除架构:

hibernate.hbm2ddl.auto = create-drop

现在每次测试之前

  • 创建应用程序上下文并注入所需的spring bean(spring)
  • 创建数据库结构(休眠)
  • 执行import.sql(如果存在)(hibernate)

并在每次测试后

  • 应用程序上下文被破坏(春天)
  • 删除数据库模式(休眠)。

如果您正在使用交易,则可能需要添加TransactionalTestExecutionListener

答案 1 :(得分:4)

How to shutdown Derby in-memory database Properly

给了我一个解决方案的提示:

    mydb.drop.url = jdbc:derby:memory:mydb;drop=true

    ...

    <bean id="mydbDropUrl" class="java.lang.String">
    <constructor-arg value="${mydb.drop.url}" />
</bean>

    ...

    @Resource
private String mydbDropUrl;        

    @After
public void tearDown() {
    try {
        DriverManager.getConnection(mydbDropUrl);
    } catch (SQLException e) {
        // ignore
    }
}

缺点是使用String构造函数接受String(围绕不可变String对象的不可变String对象)。我读到Spring 3中有一个@Value注释,这可能对此有所帮助,但我使用的是Spring 2.5。

如果您有更好的解决方案,请告诉我。

答案 2 :(得分:2)

在春季测试3之后,您可以使用注释来注入配置:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring-test.xml")
public class MyTest {
}

答案 3 :(得分:1)

如果您使用 spring-test.jar 库,则可以执行以下操作:

public class MyDataSourceSpringTest extends
AbstractTransactionalDataSourceSpringContextTests {

    @Override
    protected String[] getConfigLocations() {
        return new String[]{"classpath:test-context.xml"};
    }

    @Override
    protected void onSetUpInTransaction() throws Exception {
        super.deleteFromTables(new String[]{"myTable"});
        super.executeSqlScript("file:db/load_data.sql", true);
    }
}

基于最新评论的更新版本,在每次测试之前删除db并重新创建表:

public class MyDataSourceSpringTest extends
    AbstractTransactionalDataSourceSpringContextTests {

        @Override
        protected String[] getConfigLocations() {
            return new String[]{"classpath:test-context.xml"};
        }

        @Override
        protected void onSetUpInTransaction() throws Exception {
            super.executeSqlScript("file:db/recreate_tables.sql", true);
        }
}

答案 4 :(得分:1)

做一些像:

public class DatabaseTest implements ApplicationContextAware {
    private ApplicationContext context;
    private DataSource source;

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.context = applicationContext;
    }

    @Before
    public void before() {
        source = (DataSource) dataSource.getBean("dataSource", DataSource.class);
    }

    @After
    public void after() {
        source = null;
    }
}

让你的bean具有原型范围(scope="prototype")。这将在每次测试之前获得数据源的新实例。

答案 5 :(得分:0)

这是我们在每次测试开始时所做的事情。

  1. 删除所有以前的对象。

  2. 创建create_table.sql

  3. 中提到的所有表
  4. 根据您要测试的内容将值插入到创建的表中。

      @Before
      public void initialInMemoryDatabase() throws IOException, FileNotFoundException {
    
      inMemoryDerbyDatabase.dropAllObjects();
      inMemoryDerbyDatabase.executeSqlFile("/create_table_policy_version_manager.sql");
      inMemoryDerbyDatabase.executeSqlFile("/insert_table_policy_version_manager.sql");
    
      }
    
  5. 像魅力一样!