Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Test-driven development with Quarkus

November 8, 2021
Eric Deandrea
Related topics:
JavaKubernetesMicroservicesQuarkusSpring Boot
Related products:
Red Hat OpenShift

    Want to learn more about developing applications with Quarkus? Download our free e-book Quarkus for Spring Developers, which helps Java developers familiar with Spring make a quick and easy transition.

    Many development teams today have adopted test-driven development (TDD). Continuous testing support in Quarkus enables developers to take advantage of this practice. When running Quarkus Dev Mode, you can enable continuous testing with the press of a key, empowering Quarkus to automatically rerun tests affected by a code change in the background.

    Quarkus understands which tests are affected by classes and methods within the application. As you make code changes, you get immediate feedback if the change passes your existing test suite. This capability is integrated directly into Quarkus—no IDE or special tooling is required. The future of developer productivity and joy is now!

    This article walks you through a TDD approach to building an application and highlights the benefits that Quarkus brings. The completed example you should have after completing the steps in this article can be found in this GitHub repository.

    Create a Quarkus project

    Getting started with Quarkus is very simple. All that is required is a Java 11+ JDK, Apache Maven 3.8.1+, and a terminal. An IDE (such as IntelliJ, VSCode, or Eclipse) is helpful but not required. You could go to Code Quarkus to create the project, but we are going to use a terminal instead.

    Open up a new terminal and execute:

    mvn io.quarkus.platform:quarkus-maven-plugin:2.4.1.Final:create -DprojectGroupId=com.redhat -DprojectArtifactId=quarkus-tdd -DclassName="com.redhat.tdd.TDDResource" -Dpath="/tdd" -Dextensions="resteasy-reactive-jackson"

    When complete, you should see the following message:

    [INFO] ========================================================================================
    [INFO] Your new application has been created in /path/to/quarkus-tdd
    [INFO] Navigate into this directory and launch your application with mvn quarkus:dev
    [INFO] Your application will be accessible on http://localhost:8080
    [INFO] ========================================================================================

    Run Quarkus Dev Mode

    Quarkus Dev Mode enables hot deployment with background compilation. Changes made to an application while Dev Mode is running will automatically take effect without you having to initiate a recompile or redeploy. In most cases, this happens in under a second.

    Your turn!

    cd into the newly-created quarkus-tdd directory and execute ./mvnw quarkus:dev (or mvnw quarkus:dev on Windows).

    When complete, you should see:

    __  ____  __  _____   ___  __ ____  ______ 
     --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
     -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
    --\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
    INFO  [io.quarkus] (Quarkus Main Thread) quarkus-tdd 1.0.0-SNAPSHOT on JVM (powered by Quarkus 2.4.1.Final) started in 2.218s. Listening on: http://localhost:8080
    INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
    INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]
     
    --
    Tests paused
    Press [r] to resume testing, [o] Toggle test output, [h] for more options>

    The application is now running in Dev Mode.

    Enable continuous testing

    When enabled, Quarkus continuous testing will run affected tests immediately after code changes have been saved, allowing you instant feedback on the changes just made. Quarkus also understands which tests cover which code so only relevant tests are run when changes are made.

    Your turn!

    Press r to resume testing. The entire test suite will be run the first time continuous testing is resumed. Doing this allows Quarkus Dev Mode to understand the relationships between the tests and the code they cover.

    In this case, there is only one test, so it should execute fairly quickly. When complete, you should see:

    All 1 test is passing (0 skipped), 1 test was run in 2739ms. Tests completed at 14:15:25.

    Note: The test execution time might vary for you.

    Access the Quarkus Dev UI

    The Quarkus Dev UI is a landing page that is exposed at the /q/dev URI when running in Dev Mode. The Dev UI allows you to easily browse, visualize, and interact with endpoints offered by extensions currently installed in a project. Each extension can offer its documentation, custom runtime information, full custom pages, and interactive pages with custom actions that can be performed through the Dev UI.

    Your turn!

    Press d to open the Dev UI in your browser and click the test icon, as shown in Figure 1.

    Quarkus Dev UI test icon.
    Figure 1. Quarkus Dev UI test icon.

    This will open the test UI, as shown in Figure 2.

    Screenshot of the Quarkus Test UI.
    Figure 2. Quarkus Test UI.

    Test-driven development scenario

    The remainder of this article will focus on implementing and modifying scenarios within the current application being developed. 

    1. In the current project, open src/test/java/com/redhat/tdd/TDDResourceTest.java.
    2. Remove the existing test method in the class.
    3. Add some new tests:
      @Test
      public void getAll() {
        given()
          .when().get("/tdd")
          .then()
            .statusCode(200)
            .body(
              "$.size()", is(1),
              "[0].id", is(1),
              "[0].message", is("Hello")
            );
      }
       
      @Test
      public void getOneFound() {
        given()
          .when().get("/tdd/1")
          .then()
            .statusCode(200)
            .body(
              "id", is(1),
              "message", is("Hello")
            );
      }
       
      @Test
      public void getOneNotFound() {
        given()
          .when().get("/tdd/2")
          .then().statusCode(404);
      }
      • The getAll test issues a GET request to /tdd and expects a status code of 200 and a body containing a JSON array of size 1 that contains an object having attributes id == 1 and message == Hello.
      • The getOneFound test issues a GET request to /tdd/1 and expects a status code of 200 and a body containing a JSON object having attributes id == 1 and message == Hello.
      • The getOneNotFound test issues a GET request to /tdd/2 and expects a status code of 404.
    4. As soon as you save your editor you should see some new test results in the Test UI, as shown in Figure 3. (You might need to refresh the browser page.) The tests are failing because they are calling endpoints that don't currently exist. The getOneNotFound test is passing because the test is asserting that a particular endpoint doesn't return any results, which currently is the case.
      Screenshot of the Test UI after the first run.
      Figure 3. Quarkus test results (1).
    5. Create a new class src/main/java/com/redhat/tdd/Item.java with the following contents:
      package com.redhat.tdd;
       
      public class Item {
        private Long id;
        private String message;
       
        public Item() {
        }
       
        public Item(Long id, String message) {
          this.id = id;
          this.message = message;
        }
       
        public Long getId() {
          return this.id;
        }
       
        public void setId(Long id) {
          this.id = id;
        }
       
        public String getMessage() {
          return this.message;
        }
       
        public void setMessage(String message) {
          this.message = message;
        }
      }
    6. Save Item.java.
    7. Open src/main/java/com/redhat/tdd/TDDResource.java.
    8. Add a new attribute to the class:
      private final List items = List.of(new Item(1L, "Hello"));
    9. Remove all existing methods from the class.
    10. Add a new method that implements the GET to the /tdd endpoint:
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public List<Item> getAll() {
        return items;
      }
    11. Save your editor and return to the Test UI to see the updated test results, as shown in Figure 4. You might need to refresh the browser page. The getAll test now passes.
      Screenshot of Test UI after second run.
      Figure 4. Updated test results.
    12. The functionality implemented by the getOneFound test now needs to be implemented. Still in the TDDResource class, add an additional method that implements the GET to the /tdd/{id} endpoint. This endpoint should return a 200 status code with a JSON representation of the object with id equal to {id}, if one exists. If the id is not found, it should return a 404 status code.
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      @Path("/{id}")
      public Response getOne(@PathParam("id") Long id) {
        return items.stream()
          .filter(item -> id == item.getId())
          .findFirst()
          .map(item -> Response.ok(item).build())
          .orElseGet(() -> Response.status(Status.NOT_FOUND).build());
      }
    13. Save your editor and return to the Test UI and see updated test results, as shown in Figure 5. The completed TDDResource class should be:
      package com.redhat.tdd;
       
      import java.util.List;
       
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.PathParam;
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.core.Response;
      import javax.ws.rs.core.Response.Status;
       
      @Path("/tdd")
      public class TDDResource {
        private final List<Item> items = List.of(new Item(1L, "Hello"));
       
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public List<Item> getAll() {
          return items;
        }
       
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        @Path("/{id}")
        public Response getOne(@PathParam("id") Long id) {
          return items.stream()
            .filter(item -> id == item.getId())
            .findFirst()
            .map(item -> Response.ok(item).build())
            .orElseGet(() -> Response.status(Status.NOT_FOUND).build());
        }
      }
      Screenshot of Test UI after resource tests pass.
      Figure 5. All tests passing.
    14. Now let's refactor some of the logic into a service class that the resource layer calls rather than the resource layer maintaining the application state. Create a new class src/main/java/com/redhat/tdd/TDDService.java with the following contents:
      package com.redhat.tdd;
       
      import java.util.List;
      import java.util.Optional;
       
      import javax.enterprise.context.ApplicationScoped;
       
      @ApplicationScoped
      public class TDDService {
        private final List<Item> items = List.of(new Item(1L, "Hello"));
       
        public List<Item> getAllItems() {
          return items;
        }
       
        public Optional<Item> getItem(Long id) {
          return items.stream()
            .filter(item -> id == item.getId())
            .findFirst();
        }
      }
    15. Now let's create some tests for this service. Create a new test class src/test/java/com/redhat/tdd/TDDServiceTests.java with the following contents:
      package com.redhat.tdd;
       
      import static org.junit.jupiter.api.Assertions.*;
      import org.junit.jupiter.api.Test;
       
      class TDDServiceTests {
        TDDService service = new TDDService();
       
        @Test
        public void getAllItems() {
          var items = service.getAllItems();
          assertTrue(items.size() == 1);
       
          var item = items.get(0);
          assertNotNull(item);
          assertEquals(1L, item.getId());
          assertEquals("Hello", item.getMessage());
        }
       
        @Test
        public void getItemFound() {
          var item = service.getItem(1L);
          assertNotNull(item);
          assertTrue(item.isPresent());
          assertEquals(1L, item.get().getId());
          assertEquals("Hello", item.get().getMessage());
        }
       
        @Test
        public void getItemNotFound() {
          var item = service.getItem(2L);
          assertNotNull(item);
          assertTrue(item.isEmpty());
        }
      }
    16. Save all editors and return to the Test UI to see updated test results, as shown in Figure 6. You might need to refresh your browser. All tests should be passing.
      All service and resource tests passing.
      Figure 6. All service and resource tests passing.
    17. Now we need to refactor the TDDResource class to use the new TDDService. Luckily, we now have a test suite that can make sure our refactoring doesn't affect the application's functionality! Reopen src/main/java/com/redhat/tdd/TDDResource.java and update it to the following:
      package com.redhat.tdd;
       
      import java.util.List;
       
      import javax.inject.Inject;
      import javax.ws.rs.GET;
      import javax.ws.rs.Path;
      import javax.ws.rs.PathParam;
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.MediaType;
      import javax.ws.rs.core.Response;
      import javax.ws.rs.core.Response.Status;
       
      @Path("/tdd")
      public class TDDResource {
        @Inject
        TDDService service;
       
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public List<Item> getAll() {
          return service.getAllItems();
        }
       
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        @Path("/{id}")
        public Response getOne(@PathParam("id") Long id) {
          return service.getItem(id)
            .map(item -> Response.ok(item).build())
            .orElseGet(() -> Response.status(Status.NOT_FOUND).build());
        }
      }
    18. Return to the Test UI. All tests should still be passing.
    19. Return to the terminal where quarkus:dev is running. You should see the following, indicating that only tests for the TDDResource class were run:
      --
      All 6 tests are passing (0 skipped), 2 tests were run in 1255ms. Tests completed at 14:54:44 due to changes to TDDResource.class.
    20. Press q in the terminal where quarkus:dev is running to quit the application.

    As you can see from this quick tutorial, continuous testing works across class creation as well as refactoring within an application. Quarkus understands which tests cover code and only reruns affected tests.

    The completed example you should have after completing the steps in this article can be found on GitHub.

    Where to learn more

    There are many free resources available for learning about and getting started with Quarkus. Why wait for the future? Since its inception in 2019 and continuing today and into the future, Quarkus has provided a familiar and innovative framework for Java developers, supporting capabilities developers need and want today.

    Check out these available resources:

    • Read Quarkus for Spring Developers to learn about what challenges led to Quarkus and see side-by-side examples of familiar Spring concepts, constructs, and conventions.
    • Find out why you should choose Quarkus over Spring for microservices development.
    • Discover why organizations believe the developer experience is just as important as the product itself.
    • Explore Quarkus quick starts in the Developer Sandbox for Red Hat OpenShift, which offers a free and ready-made environment for experimenting with containerized applications.
    • Try free 15-minute interactive learning scenarios.
    • Get started with Quarkus on your own.
    • Learn about Quarkus's Spring compatibility features.
      • Find out why, in some instances, there might not be any code changes needed to run a Spring application on Quarkus.
      • Get hands-on converting a Spring Boot application to Quarkus with little-to-no code changes.
    • Attend a Quarkus World Tour event when it comes to a city near you. You can even request a private stop.
    Last updated: March 13, 2023

    Related Posts

    • Why should I choose Quarkus over Spring for my microservices?

    • Quarkus for Spring developers: Getting started

    • Quarkus for Spring developers: Kubernetes-native design patterns

    • Learn Quarkus faster in the Developer Sandbox for Red Hat OpenShift

    • Spring Boot on Quarkus: Magic or madness?

    • Enhancing the development loop with Quarkus remote development

    Recent Posts

    • Confidential virtual machine storage attack scenarios

    • Introducing virtualization platform autopilot

    • Integrate zero trust workload identity manager with Red Hat OpenShift GitOps

    • Best Practice Configuration and Tuning for Linux and Windows VMs

    • Red Hat UBI 8 builders have been promoted to the Paketo Buildpacks organization

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility