我意识到最佳实践可能会建议在每个@Test方法上加载测试数据,但是这对于DBUnit而言可能会非常缓慢,因此我想出了以下解决方案,每个类只能加载一次:
>每个测试类别仅加载一次数据集
>支持多个数据源以及ApplicationContext中未命名为“ dataSource”的数据源
>并非严格要求回滚插入的DBUnit数据集
虽然下面的代码有效,但令我感到困扰的是我的Test类在类ClassClassApplicationApplicationContext()之前有静态方法,但由于它是静态的,所以不能属于接口.因此,以非类型安全的方式使用我对Reflection的使用.有没有更优雅的解决方案?
/**
* My Test class
*/
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DbunitLoadOnceTestExecutionListener.class})
@ContextConfiguration(locations={"classpath:resources/spring/applicationContext.xml"})
public class TestClass {
public static final String TEST_DATA_FILENAME = "Scenario-1.xml";
public static void beforeClassWithApplicationContext(ApplicationContext ctx) throws Exception {
DataSource ds = (DataSource)ctx.getBean("dataSourceXyz");
IDatabaseConnection conn = new DatabaseConnection(ds.getConnection());
IDataSet dataSet = DbUnitHelper.getDataSetFromFile(conn, TEST_DATA_FILENAME);
InsertIdentityOperation.CLEAN_INSERT.execute(conn, dataSet);
}
@Test
public void somethingToTest() {
// do stuff...
}
}
/**
* My new custom TestExecutioner
*/
public class DbunitLoadOnceTestExecutionListener extends AbstractTestExecutionListener {
final String methodName = "beforeClassWithApplicationContext";
@Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestClass(testContext);
Class<?> clazz = testContext.getTestClass();
Method m = null;
try {
m = clazz.getDeclaredMethod(methodName, ApplicationContext.class);
}
catch(Exception e) {
throw new Exception("Test class must implement " + methodName + "()", e);
}
m.invoke(null, testContext.getApplicationContext());
}
}
我曾经想到的另一种想法可能是创建一个静态单例类,以保存对ApplicationContext的引用,并从DbunitLoadOnceTestExecutionListener.beforeTestClass()填充它.然后,我可以从TestClass上定义的标准@BeforeClass方法中检索该单例引用.我上面调用每个TestClass的代码看起来有些混乱.
解决方法:
在得到Matt和JB的有益反馈之后,这是实现所需结果的简单得多的解决方案
/**
* My Test class
*/
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, DbunitLoadOnceTestExecutionListener.class})
@ContextConfiguration(locations={"classpath:resources/spring/applicationContext.xml"})
public class TestClass {
private static final String TEST_DATA_FILENAME = "Scenario-1.xml";
// must be static
private static volatile boolean isDataSetLoaded = false;
// use the Qualifier to select a specific dataSource
@Autowired
@Qualifier("dataSourceXyz")
private DataSource dataSource;
/**
* For performance reasons, we only want to load the DBUnit data set once per test class
* rather than before every test method.
*
* @throws Exception
*/
@Before
public void before() throws Exception {
if(!isDataSetLoaded) {
isDataSetLoaded = true;
IDatabaseConnection conn = new DatabaseConnection(dataSource.getConnection());
IDataSet dataSet = DbUnitHelper.getDataSetFromFile(conn, TEST_DATA_FILENAME);
InsertIdentityOperation.CLEAN_INSERT.execute(conn, dataSet);
}
}
@Test
public void somethingToTest() {
// do stuff...
}
}
类DbunitLoadOnceTestExecutionListener不再需要,已被删除.它只是表明,阅读所有奇特的技巧有时可能会使您自己的判断蒙蔽:o)