Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TestContainers - Joker conf 2017

TestContainers - Joker conf 2017

Sergei Egorov

November 04, 2017
Tweet

More Decks by Sergei Egorov

Other Decks in Programming

Transcript

  1. About me • Work at Uvita GmbH, Berlin • Apache

    Groovy committer • TestContainers’ co-maintainer • In love with Docker since 2013 @bsideup
  2. Unit testing • Simulation tests are green, yay! • Everything

    is mocked • DB is written by others, why should I test it? @bsideup
  3. 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
  4. 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
  5. 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
  6. 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
  7. Declarative YAML redis:
 image: redis
 ports:
 - "6379:6379"
 postgres:
 image:

    postgres
 ports:
 - "5432:5432"
 elasticsearch:
 image: elasticsearch:5.0.0
 ports:
 - "9200:9200"
 @bsideup
  8. 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
  9. 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
  10. 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
  11. As simple as PostgreSQLContainer postgresql = new PostgreSQLContainer()
 
 GenericContainer

    redis = new GenericContainer("redis:3")
 .withExposedPorts(6379) @bsideup
  12. Use case #1: testing of microservices • REST service •

    Java, Spring Boot • Redis and PostgreSQL • Calls some other micro-services @bsideup
  13. @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
  14. @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
  15. @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
  16. 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
  17. 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
  18. Use case #2: Docker as Selenium driver • Selenium/Selenide tests

    • No need to install Chrome/Firefox/etc • CI friendly @bsideup
  19. @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
  20. @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
  21. @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
  22. • http://testcontainers.org • testcontainers/testcontainers-java-examples • Integration testing is a must

    • Docker works great for testing • Unified env for Dev and CI @bsideup