10

I have integration tests that are executed on top on inmemory database. The signature of each test looks more or less like this:

@RunWith(SpringRunner.class)
@SpringBootTest
@Sql("/clean-data-in-all-tables.sql")
public class SomeTest { 
    @Test
    public void shouldDoSomehting() {}
}

During test-context initialization the DB schema is recreated by Hibernate:

spring:
  jpa:
    hibernate:
      ddl-auto: create-drop

I expect sql script to be executed after initialization of context and after db schema generation. However in some cases clean-data-in-all-tables.sql is executed before schema generation and it fails because it expects tables which were not yet created.

I have more than 500 tests written in the way I explained and they all were working well until I added few more similar tests.

Tests fail when I execute them together via Gradle or IntelliJ. Note the failed tests are not the tests which were recently added. This are the old tests totally unrelated to the ones I added. What is also strange is that the failed tests work well if I run them one by one through IntelliJ.

It looks like a bug of spring-boot however I still try to find a way to workaround it. At the same time I tried numerous of things to solve the issue however none of them was helpfull.

Please share your ideas on what could help and what could be wrong with my code.

UPDATE: Found the workaround: changing the spring.jpa.hibernate.ddl-auto from create-drop to create solves the problem.

But the question is still open what is the reason of such strange behaviour?

Community
  • 1
  • 1
Sasha Shpota
  • 9,436
  • 14
  • 75
  • 148

1 Answers1

2

One possible solution (I'm not sure if you are open for using DBUnit) can be:

1) Create Abstract Repository Integration Test:

@TestExecutionListeners({DbUnitTestExecutionListener.class})
@SpringApplicationConfiguration(classes = Application.class)
@DirtiesContext
public abstract class AbstractRepositoryIT extends AbstractTransactionalJUnit4SpringContextTests {
}

2) Create "real" integration test:

@DatabaseSetup(SomeEntityRepositoryIT.DATASET)
@DatabaseTearDown(type = DatabaseOperation.DELETE_ALL, value = {"dataset.xml})
public class SomeEntityRepositoryIT extends AbstractRepositoryIT {
...
}

In file dataset.xml you can set up initial state for your tests etc... More can be found here

nick79
  • 417
  • 3
  • 7
  • Thank you. Unfortunately I can't use DbUnit. It is more important what is wrong with my existing test configuration. – Sasha Shpota May 11 '17 at 12:31
  • Yes I understand that. But one more question - sql file is called "clean-data-in-all-tables.sql" - is it only used to delete (rollback) all data inserted into database during tests? Maybe you can end up with some solution where you don't need it? Something like using @Transactional on your test classes? – nick79 May 11 '17 at 12:43
  • We used to use `@DirtiesContext` for cleaning the DB however it increases time consumed by test run in 2-3 times. – Sasha Shpota May 11 '17 at 12:46
  • One more question - do you have some custom made task in gradle for running tests? Do you "play" with properties like maxParallelForks and forkFor and then your tests run in parallel and that's the reason why some falling when you run all of them, and not falling when you run one by one? – nick79 May 11 '17 at 12:50
  • No, gradle task is not changed in any way – Sasha Shpota May 11 '17 at 13:12