Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am looking for the recommended approach for populating test data programmatically in integration tests using spring / spring boot. I am using HSQLDB (inmemory).

There is the possibility to execute SQL scripts in spring for integration tests like this:

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

Instead of writing SQL scripts I would like to insert data for multiple test methods in one integration test programmatically like this:

@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());
    }

}

Each Test of this example runs just fine when being executed separately. But the second one (getByIsbn) will fail, when running them together. So obviously @Before is the wrong annotation to use here, since the books will be inserted twice.

How can I enforce the database setup being executed only once?

like image 608
fischermatte Avatar asked Jan 25 '16 23:01

fischermatte


People also ask

How are you going to create an ApplicationContext in an integration test?

To create integration test in Spring make sure that you have Spring Test in your dependencies and, for example, JUnit. Then you need to put annotation @RunWith(SpringRunner. class) on the test class. And also add Context Configuration to your test with a list of configs in annotation @ContextConfiguration.

Can JUnit be used for integration testing?

And what are they using it for? Even after 20 years of JUnit's existence it is still mostly being used for unit tests. If you are lucky you may see an integration test or two. JUnit is, in fact, much more than a unit testing framework.


1 Answers

Replacing @IntegrationTest with @Transactional (at the class level) should likely solve your problem.

Reasoning:

  1. @IntegrationTest launches your entire Spring Boot application, but this appears to be overkill for your scenario.
  2. @Transactional will cause your tests to execute within a test-managed transaction that will be rolled back after the test completes; code executed within the @Before method will be executed inside the test-managed transaction.
like image 58
Sam Brannen Avatar answered Apr 28 '23 06:04

Sam Brannen