Upload
pavel-rabetski
View
46
Download
2
Embed Size (px)
Citation preview
Reproducible component tests for microservices using Docker
Pavel Rabetski
Component tests
● Verify behaviour of a component
● Cheaper to maintain than system tests
● Easier to locate problems compared to system tests
Monolithic app vs Micro Services
Monolithic appMS1
MS3
MS2
MS4
● same lifecycle● same runtime/environment● component is a “grey box”
● different lifecycle● different runtime/environment● component is a “black box”
Component tests
Test script MS
Test env
Component tests
S0 S1T1:
S0 S2T2:
S0 S3T3:
Test script
Component tests: tests in sequence
S0 S1T1:
S1 ?T2:
Component tests: repeat same test
S0 S3T3:
S3 ?T3:
Approach 1: cleanup/reset state
S0 S1T1:
S1 S0T1 cleanup:
S0 S2T2:
S2 S0T2 cleanup:
Extra development effort: keep track of changes and add cleanup code
Not always possible: e.g. deleting an entity just marks delete property = true
Approach 2: separate contexts
Sx SnTn:UserId=n
S0 S1T1:UserId=1
Extra development effort: keep track of the unique context
Not always possible: if we have a global resource or complex pre-generated data
S1 S2T2:UserId=2
Alternative approach: recreate test environment
Test script
Less development effort: no need to separate contexts or clean up after test
No constraints from previous methods: possible with global resource or pre-generated data
MS
Test env
MS
Test env
MS
Test env
Alternative approach: recreate test environment
Monolithic app
Alternative approach: recreate test environment
Monolithic app
Alternative approach: recreate test environment
Monolithic app
MS
pavradev/dockerbayApache 2.0
It is Java library for component testingIt does orchestrate docker environmentIt uses JUnit and Docker Java Client
Example: Hotel booking web app
webapp
db
service webapp
db service
Maven dependency
<dependency> <groupId>com.github.pavradev</groupId> <artifactId>dockerbay</artifactId> <version>${dockerbay.version}</version> <scope>test</scope></dependency>
Configuring dockerbay: JUnit Rule
@Rulepublic DockerRule dockerRule = DockerRule.getDefault() .addContainer(postgresContainer) .addContainer(reviewsMockContainer) .addContainer(webappContainer);
Configuring dockerbay: db container
private ContainerConfig postgresContainer = ContainerConfig.builder() .withImage("postgres:9") .withName("postgres") .waitForLogEntry("database system is ready to accept connections") .build();
Configuring dockerbay: webapp container
private ContainerConfig webapp = ContainerConfig.builder() .withImage("demo/webapp") .withName("webapp") .waitForUrl("/api/hotels") .withExposedTcpPort(8082) .build();
Configuring dockerbay: service container
private ContainerConfig reviewsMockContainer = ContainerConfig.builder() .withImage("ekino/wiremock:2.1.11") .withName("reviews-mock") .withExposedTcpPort(8083) .withCmd(Arrays.asList("--port", "8083", "--verbose")) .build();
Add tests
public class WebappCT {@Testpublic void shouldGetHotelWithReviews() { ...}@Testpublic void shouldUpdateHotel() { ...}@Testpublic void shouldDeleteHotel() { ...}}
Add tests@Testpublic void shouldUpdateHotel() { //create dummy hotel reqSpec.contentType(ContentType.JSON) .body("{\"name\":\"Dummy hotel\",\"address\":\"Dummy address\",\"zip\":\"4001\"}") .post("/api/hotels"); //update dummy hotel address reqSpec.contentType(ContentType.JSON) .body("{\"address\":\"Updated address\",\"zip\":\"4004\"}") .put("/api/hotels/1"); //validate address updated reqSpec.get("/api/hotels/1") .then() .assertThat() .body("address", equalTo("Updated address"));}
Add tests@Testpublic void shouldGetHotelWithReviews() { //create dummy hotel reqSpec.contentType(ContentType.JSON) .body("{\"name\":\"Dummy hotel\",\"address\":\"Dummy address\",\"zip\":\"4001\"}") .post("/api/hotels"); //mock GET request for hotel reviews reviewsMock.register(get(urlEqualTo("/api/reviews?hotelId=1")) .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") .withBody("[...]"))); //validate dummy hotel returned with reviews reqSpec.get("/api/hotels/1") .then().assertThat() .statusCode(200) .and().body("name", equalTo("Dummy hotel")) .and().body("reviews.size()", equalTo(1));}
Execute
dockerbay
DOCKER_HOST
Execute
pull images
DOCKER_HOST
WM
Execute
pull images
create custom network
DOCKER_HOST
WM
{id}
Execute
pull images
create custom network
create and start containers
DOCKER_HOST
WM
{id}
webapp
db service
{id}-webapp {id}-db {id}-service
Execute
pull images
create custom network
create and start containers
execute test
DOCKER_HOST
WM
{id}
webapp
db service
{id}-webapp {id}-db {id}-service
Execute
pull images
create custom network
create and start containers
stop and remove containers
execute test
DOCKER_HOST
WM
{id}
Execute
pull images
create custom network
create and start containers
stop and remove containers
execute test
remove custom network
DOCKER_HOST
WM
Parallelization
T1
T2
T3
Test script
Parallelization
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <configuration> <parallel>all</parallel> <threadCount>3</threadCount> <perCoreThreadCount>false</perCoreThreadCount> </configuration></plugin>
Questions