Share
Embed
TestContainers - Joker conf 2017
Sergei Egorov
November 04, 2017
Transcript
55 slides
-
About me • Work at Uvita GmbH, Berlin • Apache
Groovy committer • TestContainers’ co-maintainer • In love with Docker since 2013 @bsideup -
Grey box testing - we know some inner details, but
mostly use public APIs -
Unit testing • Simulation tests are green, yay! • Everything
is mocked • DB is written by others, why should I test it? @bsideup -
Integration testing https://commons.wikimedia.org/wiki/File:Cd4007.jpg • Jeez, how did it passed the
Unit testing? • Is it a smoke? @#$%! YES IT IS! • Who knew that 100w soldering gun was a bit too powerful for it? @bsideup -
System testing https://commons.wikimedia.org/wiki/File:UART_8250_Microchip.jpg • Takes a lot of time to
solder • “Oh no, the power bus is too far away from my microchip!” • Interference between the components @bsideup -
Integration testing Real-world, but isolated testing Spot the issues before
the real environment Can be run during the development You have to start real databases Should be cross-platform Slower than Unit testing Pros Cons @bsideup -
Docker Compose FTW! redis: image: redis ports: - "6379:6379" postgres:
image: postgres ports: - "5432:5432" elasticsearch: image: elasticsearch:5.0.0 ports: - "9200:9200" @bsideup -
Declarative YAML redis: image: redis ports: - "6379:6379" postgres: image:
postgres ports: - "5432:5432" elasticsearch: image: elasticsearch:5.0.0 ports: - "9200:9200" @bsideup -
No ports randomization redis: image: redis ports: - "6379:6379" postgres:
image: postgres ports: - "5432:5432" elasticsearch: image: elasticsearch:5.0.0 ports: - "9200:9200" @bsideup -
Container per test? redis: image: redis ports: - "6379:6379" postgres:
image: postgres ports: - "5432:5432" elasticsearch: image: elasticsearch:5.0.0 ports: - "9200:9200" @bsideup -
TestContainers • http://github.com/testcontainers/testcontainers-java • Wraps docker-java library • Docker environment
discovery (Win, Mac, Linux) • Will start docker-machine if it’s not started yet • Containers cleanup on JVM shutdown @bsideup -
As simple as PostgreSQLContainer postgresql = new PostgreSQLContainer() GenericContainer
redis = new GenericContainer("redis:3") .withExposedPorts(6379) @bsideup -
Use case #1: testing of microservices • REST service •
Java, Spring Boot • Redis and PostgreSQL • Calls some other micro-services @bsideup -
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class
AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } @bsideup -
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class
AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } Still using all the Spring goodies! @bsideup -
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = Initializer.class) public abstract class
AbstractIntegrationTest { @ClassRule public static PostgreSQLContainer postgreSql = new PostgreSQLContainer(); @ClassRule public static GenericContainer redis = new GenericContainer("redis:3.0.6") .withExposedPorts(6379); @ClassRule public static MockServerContainer mockServer = new MockServerContainer(); } External dependencies @bsideup -
public class MockServerContainer extends GenericContainer<MockServerContainer> { public MockServerContainer() { super("jamesdbloom/mockserver:latest");
addExposedPorts(8080); } private MockServerClient client; @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { super.containerIsStarted(containerInfo); client = new MockServerClient(getContainerIpAddress(), getMappedPort(getExposedPorts().get(0))); } } @bsideup -
public class MockServerContainer extends GenericContainer<MockServerContainer> { public MockServerContainer() { super("jamesdbloom/mockserver:latest");
addExposedPorts(8080); } private MockServerClient client; @Override protected void containerIsStarted(InspectContainerResponse containerInfo) { super.containerIsStarted(containerInfo); client = new MockServerClient(getContainerIpAddress(), getMappedPort(getExposedPorts().get(0))); } } @bsideup -
Use case #2: Docker as Selenium driver • Selenium/Selenide tests
• No need to install Chrome/Firefox/etc • CI friendly @bsideup -
@Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withDesiredCapabilities(DesiredCapabilities.chrome()) .withRecordingMode(RECORD_ALL, new
File("target")); RemoteWebDriver driver = chrome.getWebDriver(); driver.get("https://wikipedia.org"); WebElement searchInput = driver.findElementByName("search"); searchInput.sendKeys("Rick Astley"); searchInput.submit(); WebElement otherPage = driver.findElementByLinkText("Rickrolling"); otherPage.click(); boolean expectedTextFound = driver.findElementsByCssSelector("p") .stream() .anyMatch(element -> element.getText().contains("meme")); assertTrue("The word 'meme' is found on a page about rickrolling", expectedTextFound); @bsideup -
@Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withDesiredCapabilities(DesiredCapabilities.chrome()) .withRecordingMode(RECORD_ALL, new
File("target")); RemoteWebDriver driver = chrome.getWebDriver(); driver.get("https://wikipedia.org"); WebElement searchInput = driver.findElementByName("search"); searchInput.sendKeys("Rick Astley"); searchInput.submit(); WebElement otherPage = driver.findElementByLinkText("Rickrolling"); otherPage.click(); boolean expectedTextFound = driver.findElementsByCssSelector("p") .stream() .anyMatch(element -> element.getText().contains("meme")); assertTrue("The word 'meme' is found on a page about rickrolling", expectedTextFound); import org.openqa.selenium.remote.RemoteWebDriver; @bsideup -
@Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withDesiredCapabilities(DesiredCapabilities.chrome()) .withRecordingMode(RECORD_ALL, new
File("target")); RemoteWebDriver driver = chrome.getWebDriver(); driver.get("https://wikipedia.org"); WebElement searchInput = driver.findElementByName("search"); searchInput.sendKeys("Rick Astley"); searchInput.submit(); WebElement otherPage = driver.findElementByLinkText("Rickrolling"); otherPage.click(); boolean expectedTextFound = driver.findElementsByCssSelector("p") .stream() .anyMatch(element -> element.getText().contains("meme")); assertTrue("The word 'meme' is found on a page about rickrolling", expectedTextFound); @bsideup -
• http://testcontainers.org • testcontainers/testcontainers-java-examples • Integration testing is a must
• Docker works great for testing • Unified env for Dev and CI @bsideup