Using Docker For Testing Legacy Code
Transcript of Using Docker For Testing Legacy Code
USING DOCKER FOR TESTING LEGACY
@alexsotob
@alexsotob2
Alex Soto
Red Hat Engineer www.lordofthejars.com @alexsotob
Who Am I?
@alexsotob3
https://www.manning.com/books/testing-java-microservices
@alexsotob4
Questions
@alexsotob5
ENIAC
@alexsotob
Quality for your Customers
6
@alexsotob
Enable changeRefactor code
Validate functionalityThe right thing, and the thing right
Trust deployments
Testing
7
@alexsoto8
What is Legacy Code?
@alexsotob
Old Code Needs To Be Maintained
9
@alexsotob
Apply Test First Strategies
10
@alexsotob
How To Start?
11
@alexsotob
Characterization Tests
12
@alexsotob
Tests By Division
13
@alexsotob14
@alexsotob
@alexsotob
Testing Containers
docker build -t myorg/myservice:1.0.0 . docker run --rm -ti -p 8080:8080 myorg/myservice:1.0.0
docker-compose up
mvn clean test
docker-compose stop
16
Docker Run
Docker Compose Run
Run tests
Stop Docker Containers
@alexsotob17
@alexsotob
Arquillian Cube DSL
@RunWith(SpringRunner.class) @SpringBootTest(classes = PingPongController.class, webEnvironment = RANDOM_PORT) @ContextConfiguration(initializers = PingPongSpringBootTest.Initializer.class) public class PingPongSpringBootTest {
@ClassRule public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6") .withPortBinding(6379); @Autowired TestRestTemplate restTemplate;
@Test public void should_get_data_from_redis() { }
18
Spring Boot Test
Custom Initializer
Container Definitionpublic static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment("testcontainers", configurableApplicationContext.getEnvironment(), "spring.redis.host=" + redis.getIpAddress(), "spring.redis.port=" + redis.getBindPort(6379) );
Sets Container Environment
@alexsotob
Arquillian Cube Example@RunWith(Arquillian.class) public class HelloWorldTest {
@ArquillianResource @DockerUrl(containerName = "helloworld", exposedPort = 8080) RequestSpecBuilder requestSpecBuilder;
@Test public void should_receive_ok_message() { RestAssured .given() .spec(requestSpecBuilder.build()) .when() .get() .then() .assertThat().body("status", equalTo("OK")); }
}
19
Arquillian Runner
REST-Assured Integration Environment Resolver
Normal REST-Assured Call
helloworld: image: jonmorehouse/ping-pong ports: - "8080:8080"
src/test/docker/docker-compose.yml
@alexsotob
DEMO
20
@alexsotob21
Persistence Tests
@alexsotob22
APE
@alexsotob
APE SQL example
@Rule public ArquillianPersistenceRule arquillianPersistenceRule = new ArquillianPersistenceRule(); @DbUnit @ArquillianResource RdbmsPopulator rdbmsPopulator;
@Before public void populateData() { // Given: rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa") .withPassword("").usingDataSet("composers.yml") .execute();
}
23
APE JUnit Rule (not necessary with Arquillian Runner)
Set DBUnit usage
Configure Connection and Dataset
Populate
composers:
- id: 1 name: Wolfgang Amadeus Mozart birthdate: 27/1/1756 died: 5/12/1791
@alexsotob
APE SQL example
@After public void clean_database() { // Given: rdbmsPopulator.forUri(jdbcUri).withDriver(Driver.class).withUsername("sa") .withPassword("").usingDataSet("composers.yml") .clean(); }
24
Clean After Test
Clean Database
@alexsotob
Boilerplate Code
Programmatic/Declarative@UsingDataSet/@ShouldMatchDataSet
SQL SupportDBUnit and Flyway
REST API SupportPostman Collections
NoSQL SupportMongoDB, Couchbase, CouchDB, Vault, Redis, Infinispan
Benefits of Arquillian APE
25
@alexsotob26
DEMO
@alexsotob27
Visual Testing
@alexsotob
Selenium
28
@alexsotob
Arquillian Drone
29
@alexsotob
Arquillian Drone example
@RunWith(Arquillian.class) public class LoginScreenTest { @Drone private WebDriver browser; @Test public void should_login_user() { driver.get("www.mypage.com/login"); driver.findElement(By.id("loginForm:login")).click(); } }
30
Arquillian Runner
Injection of WebDriver instance
@alexsotob
Arquillian Graphene
31
@alexsotob
Arquillian Graphene Page Object example
@Location("login.xhtml") public class HomePage {
@Page private UserPage userPage;
@FindBy(id = "submit") private WebElement submitButton;
@FindBy(id = "form") private LoginPopup loginPopup;
// methods
}
32
Location of the page
Another Page Object
Find web element by id
Page fragment
@alexsotob
Arquillian Graphene example
@RunWith(Arquillian.class) public class LoginTest {
@Drone WebDriver webDriver;
@Test public void should_create_a_new_speaker(@InitialPage HomePage homePage) { homePage.login("username", "pasword"); } }
33
Open given page
Use Page Object method
@alexsotob34
Docker and Selenium
@alexsotob
DEMO
35
@alexsotob36
Let’s Wind Down
@alexsotob37
@alexsotob38
Automate Everything
@alexsotob39
@alexsotob40
Thank You
https://github.com/lordofthejars/conference-testbed
https://github.com/lordofthejars/jpa-onetomany-springboot-maven-mysql