Controlled risks: Agile integration requires automated testing

Both the development and integration of services are becoming increasingly agile and decentralized. Systems are in a constant state of flux and yet must be ready for use at all times. To prevent errors and incompatibilities from arising just as quickly with the increased speed and flexibility, an automated approach to testing is essential.

Author: Benjamin Bürgisser

In the old IT world with its fixed project phases, testing usually took place strictly after development and immediately before delivery. This often involved a separate team that was not involved in the development. A few manual end-to-end tests later it was clear: This solution does not work yet. 

With increasing speed, these time-honored software lifecycles and fixed release dates are receding into the background. Planning, development, testing and delivery of a service no longer happen in separate phases, but are performed continuously and often by a single DevOps team (see Figure 1). And because individual services and software components are rarely in a vacuum, agile integration is becoming increasingly important. Systems and their components evolve independently, are at different stages of development, and yet must always be able to interact with each other. To learn more about agile integration and its success factors, the articles by Thomas Stuber are recommended at this point: Forms of agile integration - an overview and 5 Learnings for agile integration. A particularly important factor for agile integration is its decentralization. How this can be achieved through integration as a microservice can be seen in the following article by Oliver Faust: Integration as a Microservice.

Abbildung 1 altes vs neues Vorgehen.png
Figure 1: Old waterfall model approach with fixed phases and separate teams versus the new agile approach in DevOps teams.

The challenges of agility 

The advantages of the agile approach are obvious: software systems are ready for use more quickly, potential deficits are identified earlier, changed requirements and new customer wishes are taken into account immediately, and errors are eliminated more quickly.

But it is precisely this speed that also harbors dangers. Without appropriate measures, not only the desired functions and improvements are in the productive environment more quickly, but also undesirable side effects and bugs. The elimination of one bug causes a new one in another place, the integration of one new feature renders another unusable, and the adaptation of the interface for service A causes a breaking change for service B.

In the new agile IT world, testing therefore takes on a central role. Testing is the only way to ensure that software remains executable and continues to interact correctly with other systems, even in the face of continuous change. However, separate testing teams and manually executed end-to-end tests can hardly manage such an undertaking. New solutions are required and, true to the agile approach, these are also quickly adapted, always up to date and executable at any time.

Testing in the agile world: Automating the right tests

So tests should always be up-to-date and relevant, detect problems early and, most importantly, be executed automatically and quickly whenever changes are made to the code base. Code that is not executable, contains errors or leads to breaking changes at the customers and surrounding systems should not be able to be delivered and put into production in the first place.

This results in two main tasks:

  1. Writing the right tests
  2. To execute tests automatically after every code change.

The test pyramid shows which tests should be automated

To write the right tests, the test pyramid can be consulted. This can be seen in Figure 2 and recommends a hierarchical approach to identify problems as early as possible. Tests on the lower levels of the pyramid have the highest number of test cases, are created early in the development and are executed regularly. Tests on the upper levels follow later, are more complex, more difficult to automate and usually exist in smaller numbers.

Abbildung 2 Testpyramide.png
Figure 2: The test pyramid tells in which order how many tests should be written and automated.

Unit tests form the foundation of the pyramid

Unit tests are simple, easy-to-automate tests that test the individual components of a software (units) in isolation from each other. Dependencies are replaced by mocks to keep any influences and consequential errors of other units away from the tested unit. Unit tests are white-box tests, so we know the inner workings of our system and its components.

Various tools can assist with automated unit tests. Here are the two most important ones:

  • Test frameworks provide the basis to write tests directly within the code base and execute them in the same way every time. Tests become repeatable and automatable. Recommendation: In the Java world, JUnit and TestNG have proven their worth.
  • Mocking frameworks allow the simple mocking of units. Dependencies are thus automated and replaced by a dummy implementation. Recommendation: One of the most used mocking frameworks in the Java world is Mockito, which works excellently with the above-mentioned test frameworks.

Integration tests enable error-free agile integration

Tested and correctly functioning components (units) are the prerequisite for integration tests, which ensure the correct interaction of interdependent services of an overall system. At this point, the individual service is regarded as a black box. Thus, it is no longer the correct internal functioning that counts, which has already been ensured by the unit tests. Instead, we look at the interaction of our service with other services via the respective interfaces. 

Here, too, various tools provide support:

  • Integration test frameworks allow us to simulate both clients and surrounding systems with tests that can be easily automated. This allows tests to be performed on callers and called services and ensures that the service under test behaves correctly, without the real surrounding systems having to be available. This takes much of the complexity out of integration testing and makes it fast and automated. Recommendation: Citrus has proven itself for this task at several customers. The Spring-based framework is open source and supports all the protocols a Java developer's heart desires, from REST, SOAP, JMS and Kafka to FTP and mail servers.
  • Contract testing frameworks are based on a contract between a consuming (consumer) and a producing system (producer). This contract specifies the schema and behavior of the producer's interface. Based on this, mocks can be generated for the consumer and tests for the producer. A consumer is no longer dependent on the availability of the real producer. At the same time, the producer is informed by the generated tests if a change breaks the contract, i.e. would cause a breaking change for the consumer. Recommendation: If you work with different languages and frameworks, the Pact framework is an excellent choice. It supports every conceivable technology from Java and JavaScript to Perl and Go and offers useful additional features such as the Pact Broker, which allows contracts to be managed. However, anyone working specifically with the Java Spring framework should definitely take a look at Spring Cloud Contracts, as it is perfectly integrated with Spring.

Pipelines run tests automatically

After the tests are written according to the test pyramid, it is now a matter of executing them automatically and thus preventing an untested and potentially buggy code from entering the production build. Here, too, various tools provide support:

  • Build management tools such as Maven or Gradle automatically run the tests as the software is built and only complete the build successfully if they have all run through successfully.
  • CI/CD tools and automation servers enable tests and builds to be executed automatically in a central location and the finished build to be delivered and made productive immediately using defined steps in a pipeline. Examples of such tools are Jenkins, GitLab CI/CD, Atlassian Bamboo or cloud solutions such as Azure DevOps Pipelines (Figure 3).
Abbildung 3 CI CD Tools_BBR.png
Figure 3: CI/CD tools such as Azure DevOps Pipelines can automate repetitive tasks such as build, test and deployment.

Conclusion: Preventing Breaking Changes and Creating Quality

Focusing more on tests and test automation as a key success factor in agile integration pays off in the long run. Because what looks like extra work at the beginning will more than pay off later in terms of quality and operating costs as well as agility in development and integration. 

Specifically, we enable through automated testing:

  • The early detection of problems in development
  • The fast and error-free integration of new components and features (agile integration)
  • Ensure better quality at a reasonable price, as time-consuming test phases and separate testing teams are largely eliminated
  • Keeping software and systems in an executable and productive state at all times ...
  • ... and thus ensure a faster time-to-market

To achieve these goals, we can implement the following measures:

  • Write automatable tests according to the test pyramid
  • Use contracts to prevent breaking changes
  • Use unit test and integration test frameworks such as JUnit, Citrus and Pact
  • Acquire cloud-based automation solutions such as Azure DevOps to run tests in a scalable way.

Your ipt-expert

I look forward to hearing from you

DevOps Vorgehen kostenlos anfordern

Sie möchten Ihr Unternehmen mit DevOps voranbringen, wissen aber noch nicht genau, wie Sie es angehen sollen?