Micronaut With Relation Database and...Tests
This article is a Micronauts HTTP server with a relation database persistence layer. We created this focussing on the tests at the controller layer.
Join the DZone community and get the full member experience.Join For Free
I am writing this article as I was starting to read about Micronauts.
I have been working with spring-boot over the past years, which seems very complete from my point of view. But, as I was hearing about the Micronauts project I wanted to go through and compare what I would find there with my current experience.
All the code described here is committed on my GitHub:
What Is Micronaut?
You can find a lot of literature on Micronauts, and have a lot of features:
To simplify, as I am not pretending to go through all Micronauts offers... As a basic, this framework aims to:
- Can be written in: Java (chosen on this article), Kotlin and Groovy
- Compile-time AOP and dependency injection (same mind-set as spring)
- Reactive HTTP client and server
- A suite of cloud-native features
What I will focus on this article is just an HTTP server with a relational database. We are going to do a CRD service where we have the domain object UserData, where we want (the U is not implemented on the code, but it is really straightforward):
- GET: all of them
- POST: create one
- DELETE: one
- GET: get one by id
Create the Service
When I started to create the project, I saw that it was a command-line with SDK. It seems to be the first option of the documentation, and the command line is very complete. However, there is also the link:
Which is pretty much as spring does with https://start.spring.io/.
I liked more doing on the link, but you can create the service using command line, up to you.
What We Were Looking for
What I am going to create is a service that it is very common, plain:
- Java language
- API HTTP
- JPA (Java Persistent API)
- MySQL (relational database)
This was quite straightforward to do, as with the URL above we have it all, just need select application and then on dependencies look for:
and add them on your project. Then finally you will download it in a zip file.
When we go to implement we have to:
- Create the code to make our application work (obviously...)
- Create tests to make sure that the application will continue working
It is quite common that the second point is less obvious :) However, when doing TDD the order of the steps are the other way around as the test should be the first step.
Let's Start With Coding?
What I am going to present this is to create the service based on the tests. As it would be boring to do baby steps on the article, what I have organized is based on milestones, where I am going to present the steps that has some major change.
There are three milestones, where the third one we would have the service running and returning something, based on the database.
Milestone 1 — Doing a Dummy Endpoint
If we try with the test, we can do the following, thinking to start with and endpoint GET to get all users:
Here we can see that we have:
- @MicronautTest: Which acts as @SpringBootTest starting the application on test mode
- RxHttpClient: A real client that calls the endpoint, for later to validate the response
- I am using here a third party library for assertions: Assertj. This is really optional...I could use direclty JUnit itself. You can see on github about the dependency used.
The DTO corresponds to:
We used Lombok for avoiding to write too much code, even though we have quite a lot of annotations... this is also optional. This object will become our JPA entity (I am not going to separate presentation and persistence layers, to make this simpler).
With that, the minimum code we need is:
Milestone 2 — Create Repository (Controller Dependency)
Now, I would like to go to the next step when we have a dummy repository, so we will add a dependency to the controller (the service architecture will be just controller/repository layers to have a very simple solution):
Now the controller will need to have:
We really not done much, but we added a dependency, and now I have to ways proceed with test:
- Unit test
- Integration test
As the repository is dummy, we can focus on the unit test, later on when we have database we will focus on the integration tests. So that, at a unit level, we should mock the final class dependency behaviour:
Here we have the Micronauts annotation @MockBean. This annotation enables us to mock the implementation of the dependency.
It is interesting that on spring-boot there is the same annotation, however there it automatically creates a Mockito instance of the tagged dependency. Here, on the other hand, it is more flexible, as we could create a new fresh instance implementation, not needing any third-party dependency. On this approach, it seems needed to have an interface, then we could create the new instance based on the interface.
This was a very common practice on spring, some time ago, on the projects that I have been working, it seems that the team considers this interfaces more an over-engineering, not seeing much value on this. Then I decided to create the Mockito mock instance, which it is what I am used to, and mockito give me some methods to have different behaviours per test and also verifiers. Again this is nor mandatory, but my choose.
There is another options to use @Replaces, however the @MockBean, seemed more close from what I am used to.
Milestone 3 — Add Entity Manager
On this milestone, we are going to create the real repository (I am not going to unit test this class, and this will be covered with the integration test, on a real project I would do integration test on this class to have the tests against a real database).
What we have to do is to add the EntityManager on our repository:
Here I am going directly to the JPA EntityManager, however, you could define other third party libraries, such as queydsl.
At this point, the unit test we created on the controller stays as it is. On the other hand, we can create an integration test of the controller, which will be from the API call to the database. We are going to use h2 for testing. To do so, we have to add the h2 dependency on our Gradle:
Then on the application yml (I create a brand new on the test/resources, you could use also application-test.yml):
And we have to add the column names on the data object:
With that, we are ready for our integration test:
On test code, we do not have anything new from micronaut. It was introduced just java faker, which it is totally optional, to have more randomised test data.
Here the only pain point, I faced, is the need to commit the transaction. From my point of view, this is something that is better handled, as you do not have to commit anything, all stays on the same transaction. However, on this integration test the RxHttpClient is opening another thread, and when the HTTP request reaches the repository, it is in a different transaction as we are inserting the values... then if we do not commit, the result will be always an empty list.
You will find on the documentation that the annotation @MicronautTest rollback after every test. However, when we have to commit, there is nothing to rollback...Then we may have the h2 dirty with data from one test to the others.
Milestone 4 — Add All Wanted Operations
The other methods GET/POST/DELETE is really straightforward. The only thing that I may highlight is that on the non-read-only queries we have to use the annotation:
But this is very organic from milestone 3.
All final code can be found at https://github.com/naspredam/rest-micronaut-reactive-java-users/
To sum up, I did not fall in love with this framework.
It seems to me that spring-boot is a little more advanced for development needs on API HTTP with JPA server point of view and with its tests.
Here, I list some points that I feel about Micronauts, on this experience:
- I feel that spring is much better/stronger documented
- I just saw @MicronautTest annotation for testing on Micronauts. In spring-boot I have more options for specific situations, which I feel this useful
- The commit on the transaction to be able to test the endpoint on a integration test... this is something that I could live with, but it seems tricky to have to manually clean up h2... I personally find spring-boot more elegant way to deal with this
- @MockBean annotation is kind of weird to have to create a method... I feel that spring-boot if more organic.
- Micronaut does not offer a simple way to deal with queries, as spring-boot jpa does with JpaRepositories, which it is something that I missed
- Spring offers the MockMvc, which helps to assert the responses, but I also know that we could use the library rest assured, to cover a similar approach.
If I have to decide to choose between those two, it is very likely that I would go to spring-boot.
However as a future step, I would like to see what is the performance of this framework, as this could be an important point another aspect, that was not addressed on this article.
Also, just say that this article is a very concrete example, there is muuuuuch more to see from this framework.
Hope this is helpful.
All the best!
Opinions expressed by DZone contributors are their own.