DBUnit 在每个方法之后都没有清理和插入数据库,所以测试不是独立的
Posted
技术标签:
【中文标题】DBUnit 在每个方法之后都没有清理和插入数据库,所以测试不是独立的【英文标题】:DBUnit not cleaning and insert the database after every method, so test are not independent 【发布时间】:2011-12-02 00:11:37 【问题描述】:我有一个 DAO 类的测试,我使用 DBUnit 创建和填充数据库(使用内存中的 derby)。 我在测试 dao 更新方法时遇到问题,因为它修改了数据,然后另一个测试失败了。我们都知道测试应该独立于任何其他测试,而且我知道 DBUnit 有一些工具可以在每次测试后清理和重新生成数据库。 但它不起作用!
代码是这样的(TestNG):
@BeforeMethod
public void prepareData() throws Exception
cleanAndPopulate("users");
public void cleanAndPopulate (String nameXML) throws Exception
IDatabaseConnection conn;
conn = new DatabaseConnection (sessionForTesting.connection());
InputStream is = DBconnection.class.getClassLoader()
.getResourceAsStream(nameXML + ".xml");
dataset = new FlatXmlDataSet(is);
System.out.println("*** Preparando base de datos de test");
DatabaseOperation.CLEAN_INSERT.execute(conn, dataset);
这是测试(禁用以避免附带影响):
@Test(enabled=false) // Deja la BBDD en estado erroneo!!!
public void busco_y_actualizo() throws Exception
PacoUser resultado = userdao.getById(1L);
resultado.setName("OTRO");
userdao.update(resultado);
PacoUser resultado2 = userdao.getById(1L);
AssertJUnit.assertNotNull(resultado2);
AssertJUnit.assertEquals("OTRO", resultado2.getName());
【问题讨论】:
您能提供更多信息吗?你的 cleanAndPopulate() 方法是否执行了? 【参考方案1】:这是因为 CLEAN_INSERT 在测试之前执行“CLEAN”,而不是在测试之后。
例如,如果有两个测试,test1 和 test2。 test1 和 test2 分别从 test1.xml 和 test2.xml 填充表。
test1.xml 就像
<dataset>
<table1 ... />
<table2 ... />
</dataset>
test2.xml 就像
<dataset>
<table1 ... />
</dataset>
当测试顺序是test1然后是test2时,CLEAN_INSERT会做如下操作:
-
从 table2 中删除所有内容
从 table1 中删除所有内容
将 test1.xml 中的数据插入到 table1 中
将 test1.xml 中的数据插入到 table2 中
执行测试1
从 table1 中删除所有内容
将 test2.xml 中的数据插入 table1
执行测试2
所以当 test2 执行时,table1 有来自 test2.xml 的数据,这正是我们所期望的。但是 table2 仍然包含 test1 的数据,这可能会导致一些问题。
一种解决方法是为所有 xml 文件中的每个表设置一个空行。它将确保在插入之前清理所有表。
对于上面的例子,
test1.xml 会像
<dataset>
<table1 ... />
<table2 ... />
<table1 />
<table2 />
</dataset>
test2.xml 就像
<dataset>
<table1 ... />
<table1 />
<table2 />
</dataset>
【讨论】:
很好的明确答案。令人惊讶的是,没有更好的解决方案。【参考方案2】:@After
public void after() throws SQLException
Session session = hibernateSessionFactory.openSession();
try
Work work = new Work()
@Override
public void execute(Connection connection) throws SQLException
IDatabaseConnection dbConn = null;
try
dbConn = getConnection(connection);
catch (DatabaseUnitException e)
logger.error("Exception in before", e);
Assert.fail(e.getMessage());
try
List<String> resultList = (List<String>) hibernateTemplate
.execute(new HibernateCallback()
String sql = "SELECT st.TABLE_NAME FROM INFORMATION_SCHEMA.SYSTEM_TABLES st where st. TABLE_TYPE='TABLE'";
public List<String> doInHibernate(
Session session)
throws HibernateException,
SQLException
Query query = session
.createSQLQuery(sql);
List<String> list = query.list();
return list;
);
QueryDataSet partialDataSet = new QueryDataSet(dbConn);
for (String tableName : resultList)
partialDataSet.addTable(tableName);
DatabaseOperation.DELETE_ALL.execute(dbConn,
partialDataSet);
catch (Exception e)
logger.error("Exception in after", e);
Assert.fail(e.getMessage());
finally
dbConn.close();
;
session.doWork(work);
catch (Exception e)
logger.error("Exception in after", e);
Assert.fail(e.getMessage());
finally
session.close();
protected DatabaseConnection getConnection(Connection connection)
throws DatabaseUnitException, SQLException
return new DatabaseConnection(connection, SCHEMA);
【讨论】:
【参考方案3】:确保在每个测试用例之前重置数据库以确保测试独立性。 @BeforeMethod 只在所有测试用例运行前调用一次,所以把cleanAndPopulate
放在这里是不够的。
【讨论】:
以上是关于DBUnit 在每个方法之后都没有清理和插入数据库,所以测试不是独立的的主要内容,如果未能解决你的问题,请参考以下文章
如果重写setUp和tearDown,则不会调用PHP,phpunit和dbunit - getConnection和getDataSet
在 Maven/Junit/DBUnit 项目的集成测试之前/之后创建/删除数据库的最佳方法?