我想为我的项目编写测试(spring + hibernate),对于测试,我使用内存数据库(hsqldb)。我需要用一些数据填充我的数据库。至于我,最好的方法是使用@BeforeClass方法。像这样的东西
@Transactional
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:test-applicationContext.xml")
public class UsersControllerTest {
@Autowired
private static SessionFactory sessionFactory;
@BeforeClass
public static void setUpBeforeClass() {
User u = new User();
u.setLogin("test_login");
u.setPassword("test_password");
u.setName("test_name");
Session session = sessionFactory.getCurrentSession();
session.save(u);
}
但是我不能这样做,因为在这种情况下sessionFactory将为null。如果我使用@Before方法而不是@BeforeClass,它将起作用。但我认为这不是一个好的解决方案,因为这个方法将在每个@Test方法之前运行,我不需要它。 所以我的问题很简单。当您需要在数据库中创建测试数据时,哪种解决方案最适合这种情况?
答案 0 :(得分:0)
如何简单地使用静态布尔标志来防止@Before
方法中的代码被重复执行。像这样:
public class UsersControllerTest {
private static boolean isDataSetLoaded = false;
@Autowired
private SessionFactory sessionFactory;
@Before
public void setUp() throws Exception {
if (!isDataSetLoaded) {
loadDataset();
isDataSetLoaded = true;
}
}
private void loadDataset() throws Exception {
// save various entities here
}
}
我想提请你注意上述解决方案的一个警告,这只会让我头疼:
@Transactional
支持是由Spring以非常违反直觉的方式实现的。我希望在进入测试方法之前就打开事务,但事实上它们已经在早期阶段打开了:甚至在执行@Before
注释方法之前就已经打开了。
这意味着loadDataset()
中的任何数据操作都将在与第一个测试方法相同的事务中运行,这是一个巨大的问题,因为@Transactional
的默认行为测试方法是在最后回滚。最终结果是loadDataset()
中的所有初始化步骤在firts测试方法之后被撤消,因此如果后续测试方法依赖于准备好的数据,则会失败。
当然,如果loadDataset()
中的操作愿意加入现有事务,这只是一个问题,这可以通过应用适当的事务属性来防止(例如使用TransactionTemplate
Propagation.REQUIRES_NEW
1}})。