Introduction

A simple example

testCompile "org.testcontainers:testcontainers:1.15.3"testCompile "org.testcontainers:mysql:1.15.3"
@Testpublic void testSimple() throws SQLException {
try (MySQLContainer<?> mysql = new MySQLContainer<>("mysql:5.5")
.withLogConsumer(new Slf4jLogConsumer(logger))) {
mysql.start();
ResultSet resultSet = performQuery(mysql, "SELECT 1"); int resultSetInt = resultSet.getInt(1); Assert.assertEquals("A basic SELECT query succeeds", 1, resultSetInt); }
}

Prerequisites

TestContainers with GumGum’s Advertising API

public class MySQLContainerConfig extends     MySQLContainer<MySQLContainerConfig> {
...
private static MySQLContainerConfig container;
private static String DBNAME="test_containers";
private static String USER="test_containers";
private static String PWD="test_containers";
private static String MYSQL_IMAGE = "mysql:5.5";
private MySQLContainerConfig() {
super(MYSQL_IMAGE);
}
public static MySQLContainerConfig getInstance() {
if (container == null) {
container = new MySQLContainerConfig().withDatabaseName(DBNAME)
.withUsername(USER)
.withPassword(PWD)
.withLogConsumer(new Slf4jLogConsumer(logger));
}
return container;
}
@Override public void start() {
super.start();
System.setProperty("mysql.jdbc.url", container.getJdbcUrl());
System.setProperty("mysql.username", container.getUsername());
System.setProperty("mysql.password", container.getPassword());
}
...
}
mysql.jdbc.url=${DB_URL}
mysql.username=${DB_USERNAME}
mysql.password=${DB_PASSWORD}
@Testcontainers@SpringBootTest(classes={MySQLConfig.class, JpaConfigTest.class})@ComponentScan(basePackages = {"com.gumgum.advertising.api.domain.mysql"})@Tag("integration")public class UserServiceIntegrationTest  {
@Container
public static MySQLContainerConfig containerConfig = MySQLContainerConfig.getInstance();

@Autowired
private DataSource dataSource;
@Autowired
private UsersRepository usersRepository;
private static String usersTable = "CREATE TABLE IF NOT EXISTS users (" +
" id INT NOT NULL AUTO_INCREMENT, " +
" email VARCHAR(255) NOT NULL, " +
" first_name VARCHAR(255), " +
" last_name VARCHAR(255), " +
...
" PRIMARY KEY (id), " +
" CONSTRAINT ix_users_email UNIQUE (email) )";
@Test
void injectedComponentsAreNotNull() {
Assert.assertThat(dataSource, Matchers.notNullValue());
Assert.assertThat(usersRepository, Matchers.notNullValue());
}
@Test
public void testUserRepository() throws SQLException {
Statement statement = dataSource.getConnection().createStatement();
statement.execute(usersTable);
Assert.assertEquals(IterableUtils.toList(usersRepository.findAll()).size(), 0);
usersRepository.save(mockUser()); Assert.assertEquals(IterableUtils.toList(usersRepository.findAll()).size(), 1);
}
...
}
@Configuration@EnableJpaRepositories(basePackages = {"com.gumgum.advertising.api.domain.mysql", "com.gumgum.advertising.api.commons"})@EnableTransactionManagement@PropertySource(value = "classpath:testContainersAA.properties")
@Testpublic void testUserService() throws SQLException {
Statement statement = dataSource.getConnection().createStatement();
statement.execute(usersTable);
User createdUser = userService.createUser(mockUserRequestCreate());
Assert.assertEquals(createdUser.getEmail(), "new@gumgum.com");
User updatedUser = userService.updateUser(createdUser.getId(), mockUserRequestUpdate());
Assert.assertEquals(updatedUser.getEmail(), "test@gumgum.com");
User findByUser = userService.findUserByEmail("test@gumgum.com");
Assert.assertEquals(findByUser.getEmail(), "test@gumgum.com");
}

Why adopt test containers for unit tests?

Bonus track, excluding and including tests

@Testcontainers@SpringBootTest(classes={MySQLConfig.class, JpaConfigTest.class})@ComponentScan(basePackages = {"com.gumgum.advertising.api.domain.mysql"})@Tag("integration")public class UserServiceIntegrationTest  {
test {
useJUnitPlatform {
excludeTags 'integration'
}
testLogging {
showStandardStreams = true
events("skipped", "failed", "passed")
}
}
task runIntegrationTests(type: Test) {
useJUnitPlatform {
includeTags 'integration'
}
testLogging {
showStandardStreams = true
events("skipped", "failed", "passed")
}
}

Summary

References