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?
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.
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.
Replacing @IntegrationTest
with @Transactional
(at the class level) should likely solve your problem.
Reasoning:
@IntegrationTest
launches your entire Spring Boot application, but this appears to be overkill for your scenario.@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.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With