Testing your cloud-native, Java applications

This series looks at the different types of tests you can use to ensure reliability within your cloud-native Java applications, as well as various tools and frameworks you can use to achieve this. Get hands-on experience using these testing techniques and tools and test applications running in Open Liberty.

Why do you need tests?

In an ideal world where we’re all perfect developers, tests wouldn’t be needed. Instead, we would simply write code and deploy it immediately into production on a Friday afternoon, without getting calls at 2am for support. Unfortunately, this is not the case. Because code is not always perfect, you still need to test your applications to have confidence that they work the way you intend them to.

Different types of tests

Unit tests – Typically, unit tests are automated tests written and run by software developers to ensure that a section of an application (known as the "unit") meets its design and behaves as intended. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure.

Integration tests – In this level of software testing, individual units and components are combined and tested as a group. The purpose of this level of testing is to expose faults in the interaction between integrated units. 

System/End-to-end/UI tests – These types of tests test the entire software product from beginning to end to ensure the application flow behaves as expected. It defines the product’s system dependencies and ensures all integrated pieces work together as expected. The main purpose of End-to-end (E2E) testing is to test from the end user’s experience by simulating real user scenarios.

Testing Pyramid

Most applications benefit from having a balanced mix of various types of automated tests to capture different types of errors. The exact composition of the mix varies depending on the nature of the project. In general, though, the amount of each type of test should roughly follow this testing pyramid shape. The bulk of your tests should be unit tests (at the bottom of the pyramid). As you move up the pyramid, your tests get larger, but–at the same time–the number of tests (the width of your pyramid) gets smaller.

If a project has large number of integrations or complex interfaces, it should have more integration and end-to-end tests. A project that is primarily focused on computation or data, should have more unit tests and fewer integration tests. The right mix depends on the nature of the project but the key is to retain the pyramid shape of the testing pyramid, that is, Unit > Integration > End-to-End Tests.

The test/time conundrum

So, tests are obviously important to ensure our applications work correctly. However, tests take time to write and are often an area of the development cycle that is de-emphasized, with developers often encouraged to move on to new feature development and spend less time on tests. Given the limited timeframe developers are often given for this stage of development, how can you use your time in the best ways to create tests that enable greater confidence in our applications? This is where tools can be really useful. The right tools enable you to test more functionality within your application in the same timeframe.

This series introduces you to various tools that can be utilized to create more effective tests for your applications.

Objectives

Upon completion of this series, you will:

  • Develop a greater understanding and appreciation of the different types of testing that can be used to verify applications, including:

    • JUnit tests
    • Functional tests
    • Test containers
    • Contract testing
  • Gain insight into the open source tools and technologies available to use these types of tests within your own application development pipelines.

  • Get hands-on experience with some of the various testing tools and frameworks including Pact, Arquillian, MicroShed, and more through interactive labs that use Open Liberty — an open source web application server.

Prerequisites

This series gives developers an introductory overview of different testing styles and tools available to enable these tests. However, a basic understanding of microservices and application architecture would be helpful. You will also need an understanding of command lines in order to undertake the tutorials included in this learning series.

Skill level

Beginner

Estimated time to complete

Approximately 2.5 hours

Modules

This series is split into two sections: a general introduction to testing styles and tools and getting hands-on experience with the tools.

A general introduction to testing styles and tools

  • 5 Java frameworks for improving your automated testing (Blog Post): Automated testing frameworks increase the speed and quality of getting your applications into production and are critical for enterprise developers. This article looks at 5 frameworks that help improve the process of automated testing.

    Unit testing:

  • Upgrade Your Automated Tests with JUnit 5 (TechTV Episode): JUnit is an open-source framework that you can use to write unit tests for Java applications. JUnit 5 (also known as Jupiter) is the latest major release of JUnit.

    Integration testing:

  • 3 ways to write function tests for Liberty (Article): Function testing is a way to describe what the system does and test that a part or function of the system works as expected. This type of black-box testing is usually done by feeding a function a specific input and verifying the output matches what is expected. Since functional testing is a form of black-box testing, a developer or tester can test the software’s functionality without knowing the internal parts of the application.

  • Run true-to-production tests on your MicroProfile and JakartaEE applications (Article): Learn about MicroShed Testing, which makes true-to-production testing better.
  • Replicating production on your laptop using the magic of containers (TechTV Episode): MicroShed testing is an open source tool that can be used to test a containerized application from outside the container to ensure that the tests are testing the exact same image that runs in production. It is a form of integration testing for Java applications. It is a useful tool for testing as close to end-to-end type system testing without actually having to stand up an instance of an entire application and all of it’s required external services.
  • Verify your microservice integrations with contract testing (Article): Learn what contract testing is and how and when to use them.
  • How – and why – to modernize your scruffy old Java applications (TechTV Episode): Contract testing is another type of integration testing. This type of testing enables you to test contract agreements between a consumer endpoint and an API provider endpoint. Contract-based test suites can be combined to cover each interaction scenario that takes place between these endpoints. Essentially, you’re creating unit tests or suites of unit tests that validate that your API endpoint connections are functioning correctly and according to your “contract.” Again, this can be especially useful in order to test the many integrations cloud-native, microservice-based applications now have without having to do expensive and complex end-to-end tests.

Getting hands-on with using these tools:

  • Building a web application with Maven (Open Liberty guide): In this guide, learn how to test Java microservices using JUnit 5, Maven, and Open Liberty. One of the benefits of building an application with a build system like Maven is that it can be configured to run a set of automated tests. You can write tests for the individual units of code outside of a running application server (unit tests), or you can write them to call the application that runs on the server (integration tests).
  • Building a web application with Gradle (Open Liberty guide): In this guide, discover how to test Java microservices using JUnit 5, Gradle, and Open Liberty. One of the benefits of building an application with a build system like Gradle is that it can be configured to run a set of automated tests. You can write tests for the individual units of code outside of a running application server (unit tests), or you can write them to call the application that runs on the server (integration tests).
  • Testing a MicroProfile or Jakarta EE application (Open Liberty guide): This guide shows you how to make use of MicroShed testing to write tests for an application that exercise the application inside of a Docker container, creating true-to-production tests.
  • Testing microservices with consumer-driven contracts (Open Liberty guide): This guide helps you know how to test Java microservices with consumer-driven contracts in Open Liberty. Contract testing is a technique for testing an integration point by isolating each microservice and checking whether the HTTP requests and responses that the microservice transmits conform to a shared understanding that is documented in a contract.
  • Testing microservices with the Arquillian managed container (Open Liberty guide): Learn how to develop tests for your microservices by using the Arquillian Liberty Managed container and JUnit with Maven on Open Liberty. Arquillian is a testing framework to develop automated functional, integration and acceptance tests for your Java applications. Arquillian sets up the test environment and handles the application server lifecycle for you so you can focus on writing tests.

Summary

Use the articles in this series to learn about different types of tests to test your Java applications. Walk through hands-on tutorials to get experience with various kinds of testing tools and techniques.

Next steps

If you’d like to learn more about testing microservices, then check out this great video tutorial series that Sebastian Daschner has created. It focuses on testing Java-based enterprise applications, and his application makes use of MicroProfile and Jakarta EE.