Running tests locally

The previous chapter covered development workflows and Continuous Delivery pipelines. It's crucial for modern enterprise applications to define an effective pipeline. However, while the CI server takes care of all build, test, and deploy steps, software engineers are still required to build and test on their local environments.

Continuous Delivery pipelines with proper tests sufficiently verify that enterprise applications work as expected. However, the shortcoming with only relying on the pipeline is that engineers receive feedback later and only after they have pushed their changes to the central repository. Whereas this is the idea behind Continuous Integration, developers still want certainty in their changes before committing them.

Committing changes that contain careless mistakes disturbs other team members by unnecessarily breaking the build. Errors that are easy to detect can be prevented by verifying the commit locally. This is certainly doable in code level tests, such as unit, component, and integration tests, which run on local environments as well. Performing code level tests before committing prevents the majority of mistakes.

When developing technical or cross-cutting concerns, such as interceptors or JAX-RS JSON mapping, engineers also want feedback before committing the changes to the pipeline. As mentioned before, system tests against actually running applications provide the most realistic verification.

For local environments, developers could write sophisticated integration tests, running on embedded containers, to receive faster feedback. However, as we saw previously, this requires quite some time and effort and still does not reliably cover all situations.

Using container technologies enables engineers to run the same software images on multiple environments, including locally. There are Docker installations available for the major operating systems. Local machines can run Docker containers in the same way as in production, setting up custom configuration or wiring up their own networks, if required.

This enables us to run fully-fledged system tests on local environments as well. Whereas this step doesn't necessarily have to be performed during development, it's helpful for developers that want to verify integrational behavior.

Developers can perform build and test steps locally, similar to the Continuous Delivery pipeline. Running steps via the command line greatly facilitates this approach. Docker run commands enable us to dynamically configure volumes, networks, or environment variables based on the local host.

In order to automate the process, the separate build, deploy, and test commands are combined into shell scripts.

The following code snippet shows one example of a Bash script that performs several steps. Bash scripts can be run on Windows as well, via Unix-console emulators:

#!/bin/bash
set -e
cd hello-cloud/

# build
mvn package
docker build -t hello-cloud .

# deploy
docker run -d 
  --name hello-cloud-st 
  -p 8080:8080 
  -v $(pwd)/config/local/application.properties:/opt/config/application.properties 
  hello-cloud

# system tests
cd ../hello-cloud-st/
mvn test

# stopping environment
docker stop hello-cloud-st

The hello-cloud application is contained in the hello-cloud/ subfolder and built with Maven and Docker. The Docker run command configures a custom properties file. This is similar to the orchestration configuration example shown in Chapter 5, Container and Cloud Environments with Java EE.

The hello-cloud-st/ directory contains system tests that connect against a running application. In order to direct the system test to the local environment, the hosts configuration of the local machine can be adapted. The Maven test run executes the system tests.

This approach enables developers to verify behavior in fully-fledged system tests that are executed in the Continuous Delivery pipelines as well as locally, if required.

If the system test scenario requires several external systems, they are equally run as Docker containers, similar to the test environment. Applications that run in container orchestration environments use logical service names to resolve external systems. The same is possible for natively running Docker containers, that are part of custom Docker networks. Docker resolves container names in containers running in the same network.

This approach is used to run all kinds of services locally and is especially useful to run mock servers.

The following snippet shows an example of the idea of running a local test environment:

#!/bin/bash
# previous steps omitted

docker run -d 
  --name assembly-line 
  -p 8181:8080 
  docker.example.com/wiremock:2.6

docker run -d 
  --name car-manufacture-st 
  -p 8080:8080 
  car-manufacture

# ...

Similar to the system test example, the WireMock server will be configured as part of the test case. The local environment needs to ensure that hostnames point to the corresponding localhost containers.

For more complex setups, it makes sense to run the services in a container orchestration cluster as well. There are local installation options for Kubernetes or OpenShift available. The container orchestration abstracts cluster nodes. It therefore makes no difference for infrastructure as code definitions, whether a cluster runs locally, as a single node, in a server environment on-premises, or in the cloud.

This enables engineers to use the very same definitions that are used in the test environments. Running a local Kubernetes installation simplifies the shell scripts to a few kubectl commands.

If installing Kubernetes or OpenShift locally is too oversized, orchestration alternatives such as Docker Compose can be used as lightweight alternatives. Docker Compose also defines multi-container environments and their configuration in infrastructure as code files - executable by a single command. It provides similar benefits as Kubernetes. Arquillian Cube is another sophisticated way of orchestrating and running Docker containers.

Automating steps locally via scripts, highly increases the developer's productivity. Running system tests on local machines benefits engineers by providing faster feedback with less disruption.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.45.5