如何以编程方式为 Spring 中的集成测试填充测试数据?

How to populate test data programmatically for integration tests in Spring?

我正在寻找使用 spring / spring 引导在集成测试中以编程方式填充测试数据的推荐方法。我正在使用 HSQLDB(在内存中)。

可以在 spring 中执行 SQL 脚本来进行这样的集成测试:

@Test
@Sql({"/test-schema.sql", "/test-user-data.sql"})
public void userTest {
    // execute code that relies on the test schema and test data
}

我不想编写 SQL 脚本,而是想在一个集成测试中以编程方式为 多个 测试方法插入数据,如下所示:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BookstoreApp.class)
@IntegrationTest
public class BookRepositoryTest {
    @Autowired
    private BookRepository bookRepository;

    @Before // not working
    public void setUp() throws Exception {
        bookRepository.save(new Book("Donald Duck 1", "Walt Disney", "0-14-020652-3"));
        bookRepository.save(new Book("Donald Duck 2", "Walt Disney", "0-14-020652-4"));
        bookRepository.save(new Book("Micky Mouse", "Walt Disney", "0-14-020652-5"));
    }

    @Test
    public void findByTitle() {
        List<Book> books = bookRepository.findByTitle("Duck");
        Assert.assertEquals(2, books.size());
    }

    @Test
    public void getByIsbn() {
        Book book = bookRepository.getByIsbn("0-14-020652-4");
        Assert.assertEquals("0-14-020652-4", book.getIsbn());
        Assert.assertEquals("Donald Duck 2", book.getTitle());
    }

}

这个例子的每个测试在单独执行时运行得很好。但是当 运行 它们在一起时,第二个 (getByIsbn) 将失败。所以显然 @Before 是这里使用的错误注释,因为书籍将被插入两次。

如何强制数据库设置只执行一次?

@IntegrationTest 替换为 @Transactional(在 class 级别)应该可以解决您的问题。

推理:

  1. @IntegrationTest 启动您的整个 Spring 引导应用程序,但这对于您的场景来说似乎有点过分了。
  2. @Transactional 将导致您的测试在测试管理的事务中执行,该事务将在测试完成后回滚; @Before 方法中执行的代码将在测试管理的事务中执行。