Boosting Test Performance With TestContainers
TestContainers can help when performing database tests. In this post, we take a look at how to squeeze some more performance out a TestContainers setup!
Join the DZone community and get the full member experience.
Join For FreeIn my previous post on testing, I described how to use TestContainers to provide realistic test environments for database tests. This comment revealed the downside:
…as noted above, there always seems to be some drawback. In this case, the overhead of starting the Docker image and everything it contains will increase your overall build time.
As a reminder, here’s the TestContainer-specific code. Note the instance member postgres
and the JUnit Rule
that re-initializes it on a per-method basis:
package be.objectify.tcexample.db;
import be.objectify.tcexample.AbstractUserDaoTest;
import be.objectify.tcexample.UserDao;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.testcontainers.containers.PostgreSQLContainer;
import play.db.Database;
public class JooqUserDaoTest extends AbstractUserDaoTest implements DbTestSupport,
TestData {
@Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();
private Database database;
@Before
public void setup() throws Exception {
// the database has all evolutions applied
database = create(postgres);
// load some test data
loadTestData(database);
}
@After
public void tearDown() {
destroy(database);
}
@Override
public UserDao dao() {
return new JooqUserDao(database);
}
}
Given that the huge increase in test duration results from Docker container start-up times, we can instead use a JUnit ClassRule
to start up one container and re-use it for every test in the class. This means you should no longer run these tests in parallel, but the performance gains massively outweigh test parallelization.
package be.objectify.tcexample.db;
import be.objectify.tcexample.AbstractUserDaoTest;
import be.objectify.tcexample.UserDao;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.testcontainers.containers.PostgreSQLContainer;
import play.db.Database;
public class FasterJooqUserDaoTest extends AbstractUserDaoTest implements DbTestSupport,
TestData {
@ClassRule
public static PostgreSQLContainer postgres = new PostgreSQLContainer();
private Database database;
@Before
public void setup() throws Exception {
database = create(postgres);
loadTestData(database);
}
@After
public void tearDown() {
destroy(database);
}
@Override
public UserDao dao() {
return new JooqUserDao(database);
}
}
The amount of time saved depends on the number of test methods in a class. I have some test classes that have upwards of 30 tests each, and in these cases, the execution time drops from minutes to seconds. Not bad for changing a couple of lines of code.
Published at DZone with permission of Steve Chaloner, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments