Realtime Testing: Micronaut, Postgres and Testcontainer
Micronaut, Java and Testcontainer

I am a developer who loves Java, Spring, Quarkus, Micronaut, Open source, Microservices, Cloud
Search for a command to run...
Micronaut, Java and Testcontainer

I am a developer who loves Java, Spring, Quarkus, Micronaut, Open source, Microservices, Cloud
No comments yet. Be the first to comment.
Micronaut is one of the promising java based frameworks in the Microservices space. Here is a series that I have started on Microservices framework based on Micronaut.
Caching with Micronaut
Spring AI Tool Calling: From Chatbot to AI Agent with @Tool Your AI is smart. It knows an enormous amount. But it's frozen. It doesn't know what time it is right now. It doesn't know what's on your ca
Spring AI Advisors API Explained Series: Spring AI Complete Course — Lecture 4 of 12Reading Time: 8 minutesLevel: Intermediate Most developers stop at ChatClient. That is enough for demos. It is not
Working with Multiple AI Models in Spring AI Spring AI Complete Course — Lecture 3 of 12Previous: Lecture 2 — ChatClient API | Next: Lecture 4 — Advisors API In production AI applications, you rarel
Spring AI ChatClient API: The Fluent Heart of AI Integration Introduction If you've ever tried integrating AI models into a Java application, you know the pain. HTTP clients, API keys scattered everywhere, vendor-specific SDKs that never quite fit. W...
What is Spring AI? — Why Java Developers Need This in 2026 Every AI tutorial you see is in Python. LangChain, LlamaIndex, OpenAI SDK — all Python. But here's the uncomfortable truth: 80% of enterprise backends run Java. So who's building AI into thos...
Till not we have been able to create the application in Micronaut using JDBC using the H2 database. We even were able to do a CRUD operation using reactive api. Any application is not going to production without test cases. If your test cases are poor, you are not sure about their performance and bugs. In this article we will explore writing test cases using Micronaut, Postgres and Testcontainers
You can find working source code at https://github.com/CODINGSAINT/super-heroes/tree/04AddingTestWithTestContainer
Why Testcontainers
Testcontainers are a great way for writing tests for your application. It largely removes the pain of mocking the objects to write your test cases. While it is OK to mock in unit tests, I started liking the Testcontainer's concept as it seems to write tests for more real cases. The responses from Third Pary API make a perfect case to mock. Here we are using POSTGRES database which our system will interact , so let us create Tests with Testcontainers.
If you have not read the previous CRUD solutions you can refer Saving Superheroes reactively: Reactive JDBC with Micronaut. It has code and explanations till now. In the previous section we used H2 as a database, now let us switch to Postgres. Anyway in the real world, there are negligible chances of using H2. We will also add test container related dependencies.
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- 04 Testcontainers Start -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<!-- 04 Testcontainers ends-->
Let us change theapplication.yml to use Postgres db rather H2
datasources:
default:
url: ${JDBC_URL:`jdbc:postgresql://localhost:5432/superhero`}
username: ${JDBC_USER:dbuser}
password: ${JDBC_PASSWORD:theSecretPassword}
driverClassName: ${JDBC_DRIVER:org.postgresql.Driver}
schema-generate: CREATE_DROP
dialect: POSTGRES
I have also updated the Repository dialect at ReactiveSuperheroRepository which are creted to work with JDBC reactive endpoints
@JdbcRepository(dialect = Dialect.POSTGRES)
public interface ReactiveSuperheroRepository extends ReactiveStreamsCrudRepository<Superhero, Long> {
@NonNull
@Override
Mono<Superhero> findById(@NonNull Long aLong);
@NonNull
@Override
Flux<Superhero> findAll();
}
If you start your system, it should work. Also, note Postgres instance must be running. I have used docker to run postgres
docker run -it --rm \
-p 5432:5432 \
-e POSTGRES_USER=dbuser \
-e POSTGRES_PASSWORD=theSecretPassword \
-e POSTGRES_DB=superhero \
postgres:11.5-alpine
Now, we will write the test cases. Before we write, we need to create an instance for Postgres to run with test containers. Below is the base class for the writing test with the Postgres container.
You can stop the docker instance from running Postgres. Testcontainer will create it while tests are run.
Start by creating a file in test resource folder called application-test.yml , which will be picked by the system as the profile test is added as default. It will also help Testcontainer to pick the Postgres container and start. Add the following content to it.
datasources:
default:
url: jdbc:tc:postgresql:12:///postgres
driverClassName: org.testcontainers.jdbc.ContainerDatabaseDriver
Create a class for Test or add the following content (annotation and body) in your test class
@Testcontainers
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@MicronautTest
class SuperHeroesTest {
@Inject
EmbeddedApplication<?> application;
Superhero superhero = null;
@Inject
@Client("/")
private StreamingHttpClient client;
}
@Testcontainers : Annotation for Testcontainer.@TestMethodOrder(MethodOrderer.OrderAnnotation.class): Run the method in the order provided, it is important as we would like to run the test in order ( create, retrieve, update, delete).@TestInstance(TestInstance.Lifecycle.PER_CLASS): Full test makes one complete cycle. @MicronautTest: Let micronaut know that it's the test and injection for embedded server and dependency happen. EmbeddedApplication<?> application: The full embedded server on which application will start and run
StreamingHttpClient : It wil help us to do Http requests on the embedded server.
Let us now add the test for all of the CRUD operations. We will use Faker to generate faker superheroes' names and power.
Here we are creating a Superhero and adding its name with Faker (if you with you can hardcode ). We are calling HTTP POST endpoint on the embedded server. It will use the database created by Postgres to run the DB query and create an entry in it. We will assert that returned user has the same values are created.
@Test
@Order(1)
void insert() {
var faker = new Faker();
var superHero = faker.superhero();
String name = superHero.name();
String prefix = superHero.prefix();
String suffix = superHero.suffix();
String power = superHero.power();
superhero = new Superhero(null, name, prefix, suffix, power);
var request = HttpRequest.POST("/rx/superhero", superhero);
var response = client.toBlocking().exchange(request, Superhero.class);
Assert.assertEquals(HttpStatus.OK, response.getStatus());
Assert.assertEquals(name, response.body().name());
Assert.assertEquals(prefix, response.body().prefix());
}
Let us retrieve the user created. Since we have created only one user, it will have id 1. We will assert tht user is same as created.
@Test
@Order(2)
void get() {
var request = HttpRequest.GET("/rx/superhero/1");
var response = client.toBlocking().exchange(request, Superhero.class);
Assert.assertEquals(HttpStatus.OK, response.getStatus());
Assert.assertEquals(superhero.name(), response.body().name());
}
Now we will update the user with PUT and assert that it has been updated with correct values
@Test
@Order(3)
void update() {
String name = superhero.name() + "_Modified";
String prefix = superhero.prefix() + "_Modified";
Superhero hero = new Superhero(1L, name, prefix, superhero.suffix(), superhero.power());
var request = HttpRequest.PUT("/rx/superhero", hero);
var response = client.toBlocking().exchange(request, Superhero.class);
Assert.assertEquals(HttpStatus.OK, response.getStatus());
Assert.assertEquals(name, response.body().name());
Assert.assertEquals(prefix, response.body().prefix());
}
DELETE will help us to purge the superhero. Let's check it we can delete .
@Test
@Order(4)
void delete() {
var request = HttpRequest.DELETE("/rx/superhero/1");
var response = client.toBlocking().exchange(request);
Assert.assertEquals(HttpStatus.NO_CONTENT, response.getStatus());
}
Now we have done everything required to write the tests with Micronaut and Testcontainers. To run it we can use /mvnw test command in the root folder of the micronaut project. Below is the image of the output on my system. You can see the docker creating the Postgres container before tests and tests getting passed.
