0

我想为我的项目(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 将为空。如果我使用@Before 方法而不是@BeforeClass,它将起作用。但我认为这不是一个好的解决方案,因为这个方法会在每个 @Test 方法之前运行,我不需要它。所以我的问题很简单。当您需要在数据库中创建测试数据时,哪种解决方案最适合这种情况?

4

1 回答 1

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
    }
}

更新:

我想提请您注意上述解决方案的一个警告,该解决方案只是让我非常头痛:

@TransactionalSpring 以一种非常违反直觉的方式实现了该支持。我希望在进入测试方法之前打开事务,但实际上它们已经在更早的阶段打开了:甚至在@Before执行带注释的方法之前。

这意味着任何数据操作都loadDataset()将在与第一个测试方法相同的事务中运行,这是一个巨大的问题,因为@Transactional测试方法的默认行为是在最后回滚。最终结果是,在第一个测试方法之后,所有初始化步骤loadDataset()都被撤消,因此如果后续测试方法依赖于准备好的数据,它们将失败。

当然,这只是一个问题,如果其中的操作loadDataset()愿意加入现有事务,可以通过应用适当的事务属性(例如使用TransactionTemplatewith Propagation.REQUIRES_NEW)来防止这种情况。

于 2013-03-07T14:39:01.350 回答