eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

eBook – Guide Spring Cloud – NPI (cat=Cloud/Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

1. Overview

Quarkus makes it very easy these days to develop robust and clean applications. But how about testing?

In this tutorial, we’ll take a close look at how a Quarkus application can be tested. We’ll explore the testing possibilities offered by Quarkus and present concepts like dependency management and injection, mocking, profile configuration, and more specific things like Quarkus annotations and testing a native executable.

2. Setup

Let’s start with the basic Quarkus project configured in our previous Guide to QuarkusIO.

First, we’ll add the quarkus-reasteasy-jackson, quarkus-hibernate-orm-panache, quarkus-jdbc-h2, quarkus-junit5-mockito, and quarkus-test-h2 Maven dependencies:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-jdbc-h2</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5-mockito</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-test-h2</artifactId>
</dependency>

Next, let’s create our domain entity:

public class Book extends PanacheEntity {
    private String title;
    private String author;
}

We continue by adding a simple Panache repository with a method to search for books:

public class BookRepository implements PanacheRepository {

    public Stream<Book> findBy(String query) {
        return find("author like :query or title like :query", with("query", "%"+query+"%")).stream();
    }
}

Now, let’s write a LibraryService to hold any business logic:

public class LibraryService {

    public Set<Book> find(String query) {
        if (query == null) {
            return bookRepository.findAll().stream().collect(toSet());
        }
        return bookRepository.findBy(query).collect(toSet());
    }
}

And finally, let’s expose our service functionality through HTTP by creating a LibraryResource:

@Path("/library")
public class LibraryResource {

    @GET
    @Path("/book")
    public Set findBooks(@QueryParam("query") String query) {
        return libraryService.find(query);
    }
}

3. @Alternative Implementations

Before writing any tests, let’s ensure we have some books in our repository. With Quarkus, we can use the CDI @Alternative mechanism to provide a custom bean implementation for our tests. Let’s create a TestBookRepository that extends BookRepository:

@Priority(1)
@Alternative
@ApplicationScoped
public class TestBookRepository extends BookRepository {

    @PostConstruct
    public void init() {
        persist(new Book("Dune", "Frank Herbert"),
          new Book("Foundation", "Isaac Asimov"));
    }

}

We place this alternative bean in our test package, and because of the @Priority(1) and @Alternative annotations, we’re sure any test will pick it up over the actual BookRepository implementation. This is one way to provide a global mock that all our Quarkus tests can use. We’ll explore more narrow-focused mocks shortly, but now, let’s move on to creating our first test.

4. HTTP Integration Test

Let’s begin by creating a simple REST-assured integration test:

@QuarkusTest
class LibraryResourceIntegrationTest {

    @Test
    void whenGetBooksByTitle_thenBookShouldBeFound() {

        given().contentType(ContentType.JSON).param("query", "Dune")
          .when().get("/library/book")
          .then().statusCode(200)
          .body("size()", is(1))
          .body("title", hasItem("Dune"))
          .body("author", hasItem("Frank Herbert"));
    }
}

This test, annotated with @QuarkusTest, first starts the Quarkus application and then performs a series of HTTP requests against our resource’s endpoint.

Now, let’s make use of some Quarkus mechanisms to try and further improve our test.

4.1. URL Injection With @TestHTTPResource

Instead of hard-coding the path of our HTTP endpoint, let’s inject the resource URL:

@TestHTTPResource("/library/book")
URL libraryEndpoint;

And then, let’s use it in our requests:

given().param("query", "Dune")
  .when().get(libraryEndpoint)
  .then().statusCode(200);

Or, without using Rest-assured, let’s simply open a connection to the injected URL and test the response:

@Test
void whenGetBooks_thenBooksShouldBeFound() throws IOException {
    assertTrue(IOUtils.toString(libraryEndpoint.openStream(), defaultCharset()).contains("Asimov"));
}

As we can see, @TestHTTPResource URL injection gives us an easy and flexible way of accessing our endpoint.

4.2. @TestHTTPEndpoint

Let’s take this further and configure our endpoint using the Quarkus provided @TestHTTPEndpoint annotation:

@TestHTTPEndpoint(LibraryResource.class)
@TestHTTPResource("book")
URL libraryEndpoint;

This way, if we ever decide to change the path of the LibraryResource, the test will pick up the correct path without us having to touch it.

@TestHTTPEndpoint can also be applied at the class level, in which case REST-assured will automatically prefix all requests with the Path of the LibraryResource:

@QuarkusTest
@TestHTTPEndpoint(LibraryResource.class)
class LibraryHttpEndpointIntegrationTest {

    @Test
    void whenGetBooks_thenShouldReturnSuccessfully() {
        given().contentType(ContentType.JSON)
          .when().get("book")
          .then().statusCode(200);
    }
}

5. Context and Dependency Injection

When it comes to dependency injection, in Quarkus tests, we can use @Inject for any required dependency. Let’s see this in action by creating a test for our LibraryService:

@QuarkusTest
class LibraryServiceIntegrationTest {

    @Inject
    LibraryService libraryService;

    @Test
    void whenFindByAuthor_thenBookShouldBeFound() {
        assertFalse(libraryService.find("Frank Herbert").isEmpty());
    }
}

Now, let’s try to test our Panache BookRepository:

class BookRepositoryIntegrationTest {

    @Inject
    BookRepository bookRepository;

    @Test
    void givenBookInRepository_whenFindByAuthor_thenShouldReturnBookFromRepository() {
        assertTrue(bookRepository.findBy("Herbert").findAny().isPresent());
    }
}

But when we ran our test, it failed. That’s because it requires running within the context of a transaction, and none is active. This can be fixed simply by adding @Transactional to the test class. Or, if we prefer, we can define our own stereotype to bundle both @QuarkusTest and @Transactional. Let’s do this by creating the @QuarkusTransactionalTest annotation:

@QuarkusTest
@Stereotype
@Transactional
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface QuarkusTransactionalTest {
}

Now, let’s apply it to our test:

@QuarkusTransactionalTest
class BookRepositoryIntegrationTest

As we can see, because Quarkus tests are full CDI beans, we can take advantage of all the CDI benefits like dependency injection, transactional contexts, and CDI interceptors.

6. Mocking

Mocking is a critical aspect of any testing effort. As we’ve already seen above, Quarkus tests can make use of the CDI @Alternative mechanism. Let’s now dive deeper into the mocking capabilities Quarkus has to offer.

6.1. @Mock

As a slight simplification of the @Alternative approach, we can use the @Mock stereotype annotation. This bundles together the @Alternative and @Primary(1) annotations.

6.2. @QuarkusMock

If we don’t want to have a globally defined mock but would rather have our mock only within the scope of one test, we can use @QuarkusMock:

@QuarkusTest
class LibraryServiceQuarkusMockUnitTest {

    @Inject
    LibraryService libraryService;

    @BeforeEach
    void setUp() {
        BookRepository mock = Mockito.mock(TestBookRepository.class);
        Mockito.when(mock.findBy("Asimov"))
          .thenReturn(Arrays.stream(new Book[] {
            new Book("Foundation", "Isaac Asimov"),
            new Book("I Robot", "Isaac Asimov")}));
        QuarkusMock.installMockForType(mock, BookRepository.class);
    }

    @Test
    void whenFindByAuthor_thenBooksShouldBeFound() {
        assertEquals(2, libraryService.find("Asimov").size());
    }
}

6.3. @InjectMock

Let’s simplify things a bit and use the Quarkus @InjectMock annotation instead of @QuarkusMock:

@QuarkusTest
class LibraryServiceInjectMockUnitTest {

    @Inject
    LibraryService libraryService;

    @InjectMock
    BookRepository bookRepository;

    @BeforeEach
    void setUp() {
        when(bookRepository.findBy("Frank Herbert"))
          .thenReturn(Arrays.stream(new Book[] {
            new Book("Dune", "Frank Herbert"),
            new Book("Children of Dune", "Frank Herbert")}));
    }

    @Test
    void whenFindByAuthor_thenBooksShouldBeFound() {
        assertEquals(2, libraryService.find("Frank Herbert").size());
    }
}

6.4. @InjectSpy

If we’re only interested in spying and not replacing bean behaviour, we can use the provided @InjectSpy annotation:

@QuarkusTest
class LibraryResourceInjectSpyIntegrationTest {

    @InjectSpy
    LibraryService libraryService;

    @Test
    void whenGetBooksByAuthor_thenBookShouldBeFound() {
        given().contentType(ContentType.JSON).param("query", "Asimov")
          .when().get("/library/book")
          .then().statusCode(200);

        verify(libraryService).find("Asimov");
    }

}

7. Test Profiles

We might want to run our tests in different configurations. For this, Quarkus offers the concept of a test profile. Let’s create a test that runs against a different database engine using a customized version of our BookRepository, and that will also expose our HTTP resources at a different path from the one already configured.

For this, we start by implementing a QuarkusTestProfile:

public class CustomTestProfile implements QuarkusTestProfile {

    @Override
    public Map<String, String> getConfigOverrides() {
        return Collections.singletonMap("quarkus.resteasy.path", "/custom");
    }

    @Override
    public Set<Class<?>> getEnabledAlternatives() {
        return Collections.singleton(TestBookRepository.class);
    }

    @Override
    public String getConfigProfile() {
        return "custom-profile";
    }
}

Let’s now configure our application.properties by adding a custom-profile config property that will change our H2 storage from memory to file:

%custom-profile.quarkus.datasource.jdbc.url = jdbc:h2:file:./testdb

Finally, with all the resources and configuration in place, let’s write our test:

@QuarkusTest
@TestProfile(CustomBookRepositoryProfile.class)
class CustomLibraryResourceManualTest {

    public static final String BOOKSTORE_ENDPOINT = "/custom/library/book";

    @Test
    void whenGetBooksGivenNoQuery_thenAllBooksShouldBeReturned() {
        given().contentType(ContentType.JSON)
          .when().get(BOOKSTORE_ENDPOINT)
          .then().statusCode(200)
          .body("size()", is(2))
          .body("title", hasItems("Foundation", "Dune"));
    }
}

As we can see from the @TestProfile annotation, this test will use the CustomTestProfile. It will make HTTP requests to the custom endpoint overridden in the profile’s getConfigOverrides method. Moreover, it will use the alternative book repository implementation configured in the getEnabledAlternatives method. And finally, by using the custom-profile defined in getConfigProfile, it will persist data in a file rather than memory.

One thing to note is that Quarkus will shut down and then restart with the new profile before this test is executed. This adds some time as the shutdown/restart happens, but it’s the price to be paid for the extra flexibility.

8. Testing Native Executables

Quarkus offers the possibility to test native executables. Let’s create a native image test:

@QuarkusIntegrationTest
@QuarkusTestResource(H2DatabaseTestResource.class)
class NativeLibraryResourceIT extends LibraryHttpEndpointIntegrationTest {
}

And now, by running:

mvn verify -Pnative

We’ll see the native image being built and the tests running against it.

The @QuarkusIntegrationTest annotation instructs Quarkus to run this test against the native image, while the @QuarkusTestResource will start an H2 instance into a separate process before the test begins. The latter is needed for running tests against native executables, as the database engine is not embedded into the native image.

The @QuarkusTestResource annotation can also be used to start custom services, like TestContainers, for example. All we need to do is implement the QuarkusTestResourceLifecycleManager interface and annotate our test with:

@QuarkusTestResource(OurCustomResourceImpl.class)

You will need a GraalVM to build the native image.

Also, take notice that, at the moment, the injection does not work with native image testing. The only thing that runs natively is the Quarkus application, not the test itself.

9. Conclusion

In this article, we saw how Quarkus offers excellent support for testing our application. From simple things like dependency management, injection, and mocking to more complex aspects like configuration profiles and native images, Quarkus provides us with many tools to create powerful and clean tests.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook – Mockito – NPI (tag=Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

>> Download the eBook

eBook Jackson – NPI EA – 3 (cat = Jackson)
eBook – eBook Guide Spring Cloud – NPI (cat=Cloud/Spring Cloud)