Search code examples
javaspring-bootspring-boot-testtestcontainers

How to reuse Testcontainers between multiple SpringBootTests?


I'm using TestContainers with Spring Boot to run unit tests for repositories like this:

@Testcontainers
@ExtendWith(SpringExtension.class)
@ActiveProfiles("itest")
@SpringBootTest(classes = RouteTestingCheapRouteDetector.class)
@ContextConfiguration(initializers = AlwaysFailingRouteRepositoryShould.Initializer.class)
@TestExecutionListeners(listeners = DependencyInjectionTestExecutionListener.class)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Tag("docker")
@Tag("database")
class AlwaysFailingRouteRepositoryShould {

  @SuppressWarnings("rawtypes")
  @Container
  private static final PostgreSQLContainer database =
      new PostgreSQLContainer("postgres:9.6")
          .withDatabaseName("database")
          .withUsername("postgres")
          .withPassword("postgres");

But now I have 14 of these tests and every time a test is run a new instance of Postgres is spun up. Is it possible to reuse the same instance across all tests? The Singleton pattern doesn't help since every test starts a new application.

I've also tried testcontainers.reuse.enable=true in .testcontainers.properties and .withReuse(true), but that didn't help.


Solution

  • You can't use the JUnit Jupiter annotation @Container if you want to have reusable containers. This annotation ensures to stop the container after each test.

    What you need is the singleton container approach, and use e.g. @BeforeAll to start your containers. Even though you then have .start() in multiple tests, Testcontainers won't start a new container if you opted-in for reusability using both .withReuse(true) on your container definition AND the following .testcontainers.properties file in your home directory:

    testcontainers.reuse.enable=true
    

    A simple example might look like the following:

    @SpringBootTest
    public class SomeIT {
    
      public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
        withReuse(true);
    
      @BeforeAll
      public static void beforeAll() {
        postgreSQLContainer.start();
      }
    
      @Test
      public void test() {
    
      }
    
    }
    

    and another integration test:

    @SpringBootTest
    public class SecondIT {
    
      public static GenericContainer postgreSQLContainer = new PostgreSQLContainer().
        withReuse(true);
    
      @BeforeAll
      public static void beforeAll() {
        postgreSQLContainer.start();
      }
    
      @Test
      public void secondTest() {
    
      }
    
    }
    

    There is currently a PR that adds documentation about this

    I've put together a blog post explaining how to reuse containers with Testcontainers in detail.