<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodnan Sol</title>
    <description>The latest articles on DEV Community by Rodnan Sol (@rodnan-sol).</description>
    <link>https://dev.to/rodnan-sol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F6288%2F4c472404-fa3f-4424-ae9d-797b1c511105.png</url>
      <title>DEV Community: Rodnan Sol</title>
      <link>https://dev.to/rodnan-sol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rodnan-sol"/>
    <language>en</language>
    <item>
      <title>Testing with Maven - Organizing unit and integration tests</title>
      <dc:creator>Nándor Holozsnyák</dc:creator>
      <pubDate>Thu, 08 Jun 2023 20:36:00 +0000</pubDate>
      <link>https://dev.to/rodnan-sol/testing-with-maven-organizing-unit-and-integration-tests-35oh</link>
      <guid>https://dev.to/rodnan-sol/testing-with-maven-organizing-unit-and-integration-tests-35oh</guid>
      <description>&lt;h2&gt;
  
  
  Testing with Maven - Organizing unit and integration tests
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Testing with Maven - Organizing unit and integration tests

&lt;ul&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;How does a Maven project look like?&lt;/li&gt;
&lt;li&gt;What does Maven Surefire plugin do?&lt;/li&gt;
&lt;li&gt;Why isn't Surefire plugin good for running integration tests?&lt;/li&gt;
&lt;li&gt;Maven Failsafe Plugin&lt;/li&gt;
&lt;li&gt;How does Maven Failsafe plugin work?&lt;/li&gt;
&lt;li&gt;
How to organize tests properly in your Maven project?

&lt;ul&gt;
&lt;li&gt;Mix unit and integration tests&lt;/li&gt;
&lt;li&gt;Advantages&lt;/li&gt;
&lt;li&gt;Disadvantages&lt;/li&gt;
&lt;li&gt;Separate unit and integration tests on package level&lt;/li&gt;
&lt;li&gt;Advantages&lt;/li&gt;
&lt;li&gt;Disadvantages&lt;/li&gt;
&lt;li&gt;Separate unit and integration tests on root folder level&lt;/li&gt;
&lt;li&gt;
How to set it up?

&lt;ul&gt;
&lt;li&gt;Maven Compiler Plugin Way&lt;/li&gt;
&lt;li&gt;build-helper-maven-plugin way&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Advantages&lt;/li&gt;

&lt;li&gt;Disadvantages&lt;/li&gt;

&lt;li&gt;Surprise option: New maven module&lt;/li&gt;

&lt;li&gt;Advantages&lt;/li&gt;

&lt;li&gt;Disadvantages&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Summary&lt;/li&gt;

&lt;li&gt;Follow Rodnan Sol for more&lt;/li&gt;

&lt;li&gt;Follow the author too&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Are you making unit and integration tests in your project? I hope so! &lt;/p&gt;

&lt;p&gt;Tests are the fundamentals of a good working and quality software, nobody shouls be skipping them, even if their clients says it 🔥.&lt;/p&gt;

&lt;p&gt;If you are a Java developer you probably know the different build tools out there and their support for writing and running unit and integration tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ant&lt;/li&gt;
&lt;li&gt;Maven&lt;/li&gt;
&lt;li&gt;Gradle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You name it&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post we will be focusing on &lt;strong&gt;Maven&lt;/strong&gt;, built and maintained by ASF (Apache Software Foundation). &lt;/p&gt;

&lt;p&gt;Maven is a beautiful project that helped millions of projects go live, it is an industry standard, but nothing is perfect even millions of projects are depending on it. In this post we are not going to find all the negativity behind the Maven build tool, only just to focus on the testing topics, and to give you advices how your projects structure could be setup to enforce a better test and production code quality.&lt;/p&gt;

&lt;p&gt;If you are familiar with a setup of a Maven project, and you know how the different plugins like the Surefire and Failsafe handle the compiled test classes, then you can skip to the following section, the very first few ones are just introducing how Maven is handling the tests. If you want to refresh your knowledge do read the first chapters too! :)&lt;/p&gt;

&lt;h3&gt;
  
  
  How does a Maven project look like?
&lt;/h3&gt;

&lt;p&gt;By default, if a new projects is just initialized, it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf8jfbbdtel1moh6q7g6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf8jfbbdtel1moh6q7g6.png" alt="Basic Project Setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;UserService&lt;/code&gt; classes are just here for the example, there is no framework behind them, there is no real logic, only for the sake of demonstration.&lt;/p&gt;

&lt;p&gt;How can we execute the tests that are in our project? That is easy, just run the &lt;code&gt;mvn test&lt;/code&gt; command in your terminal.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;mvn &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Scanning &lt;span class="k"&gt;for &lt;/span&gt;projects...
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;------------------&lt;/span&gt;&amp;lt; org.rodnansol:simple-test-setup &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Building simple-test-setup 1.0-SNAPSHOT
&lt;span class="o"&gt;[&lt;/span&gt;INFO]   from pom.xml
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;--------------------------------&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; jar &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="nt"&gt;---------------------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;---&lt;/span&gt; resources:3.3.0:resources &lt;span class="o"&gt;(&lt;/span&gt;default-resources&lt;span class="o"&gt;)&lt;/span&gt; @ simple-test-setup &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;WARNING] Using platform encoding &lt;span class="o"&gt;(&lt;/span&gt;UTF-8 actually&lt;span class="o"&gt;)&lt;/span&gt; to copy filtered resources, i.e. build is platform dependent!
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Copying 0 resource
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;---&lt;/span&gt; compiler:3.10.1:compile &lt;span class="o"&gt;(&lt;/span&gt;default-compile&lt;span class="o"&gt;)&lt;/span&gt; @ simple-test-setup &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Nothing to compile - all classes are up to &lt;span class="nb"&gt;date&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;---&lt;/span&gt; resources:3.3.0:testResources &lt;span class="o"&gt;(&lt;/span&gt;default-testResources&lt;span class="o"&gt;)&lt;/span&gt; @ simple-test-setup &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;WARNING] Using platform encoding &lt;span class="o"&gt;(&lt;/span&gt;UTF-8 actually&lt;span class="o"&gt;)&lt;/span&gt; to copy filtered resources, i.e. build is platform dependent!
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;---&lt;/span&gt; compiler:3.10.1:testCompile &lt;span class="o"&gt;(&lt;/span&gt;default-testCompile&lt;span class="o"&gt;)&lt;/span&gt; @ simple-test-setup &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Nothing to compile - all classes are up to &lt;span class="nb"&gt;date&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;---&lt;/span&gt; surefire:3.0.0-M8:test &lt;span class="o"&gt;(&lt;/span&gt;default-test&lt;span class="o"&gt;)&lt;/span&gt; @ simple-test-setup &lt;span class="nt"&gt;---&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;-------------------------------------------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO]  T E S T S
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;-------------------------------------------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Running org.rodnansol.user.UserServiceTest
OpenJDK 64-Bit Server VM warning: Sharing is only supported &lt;span class="k"&gt;for &lt;/span&gt;boot loader classes because bootstrap classpath has been appended
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.645 s - &lt;span class="k"&gt;in &lt;/span&gt;org.rodnansol.user.UserServiceTest
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Results:
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
&lt;span class="o"&gt;[&lt;/span&gt;INFO]
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] BUILD SUCCESS
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Total &lt;span class="nb"&gt;time&lt;/span&gt;:  1.629 s
&lt;span class="o"&gt;[&lt;/span&gt;INFO] Finished at: 2023-06-04T17:45:29+02:00
&lt;span class="o"&gt;[&lt;/span&gt;INFO] &lt;span class="nt"&gt;------------------------------------------------------------------------&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;What happened in this case?&lt;/p&gt;

&lt;p&gt;Maven has multiple &lt;strong&gt;phases&lt;/strong&gt; that can be executed, as Maven has the &lt;code&gt;pom.xml&lt;/code&gt; file, it also has a so called &lt;strong&gt;Effective POM&lt;/strong&gt; that contains all the phase configurations, but they are not presented in the &lt;code&gt;pom.xml&lt;/code&gt; file because that would be too verbose, and it would be difficult to read. These configurations are inherited from the so-called &lt;strong&gt;Super POM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Effective POM&lt;/strong&gt; contains all the plugins that will be run when a specific phase is executed, the phases are backed by plugins, like the &lt;strong&gt;maven-clean-plugin&lt;/strong&gt;, &lt;strong&gt;maven-compiler-plugin&lt;/strong&gt; and the &lt;strong&gt;maven-surefire-plugin&lt;/strong&gt; for example that is executing any tests.&lt;/p&gt;

&lt;p&gt;Do not here is that the &lt;strong&gt;maven-surefire-plugin&lt;/strong&gt; executes its &lt;code&gt;test&lt;/code&gt; goal in the &lt;code&gt;test&lt;/code&gt; phase. Even if they are having the same wording it is not the same. The other thing is also crucial, we do not see the &lt;code&gt;maven-failsafe-plugin&lt;/code&gt; here, which will be a key later.&lt;/p&gt;

&lt;p&gt;Okay, okay, I want to see it with my eyes, so how to create the effective-pom? It is easy: &lt;code&gt;mvn help:effective-pom&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As it is being more than 250 lines, let me just copy a small section of it.&lt;/p&gt;

&lt;p&gt;We can see the configuration of the &lt;strong&gt;maven-clean-plugin&lt;/strong&gt; and the &lt;strong&gt;maven-surefire-plugin&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4p7x4qcoh468158saha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl4p7x4qcoh468158saha.png" alt="Effective Pom"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  What does Maven Surefire plugin do?
&lt;/h3&gt;

&lt;p&gt;TL;DR: It executes tests.&lt;/p&gt;

&lt;p&gt;Seriously, it is executing tests, but how does it recognize tests?&lt;/p&gt;

&lt;p&gt;The plugin has configuration values, and one of them first defines the folder of the compiled test classes and the other configuration options sets the included files, it is done mostly by patterns.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test class directory: &lt;a href="https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#testclassesdirectory" rel="noopener noreferrer"&gt;https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#testclassesdirectory&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;By default: &lt;code&gt;target/test-classes&lt;/code&gt; - and it is compiled by the &lt;strong&gt;maven-compiler-plugin&lt;/strong&gt;'s &lt;strong&gt;testCompile&lt;/strong&gt; goal at the &lt;strong&gt;test-compile&lt;/strong&gt; phase. A lots of things are going there for sure. 🔥&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Included classes: &lt;a href="https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#includes" rel="noopener noreferrer"&gt;https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#includes&lt;/a&gt; 

&lt;ul&gt;
&lt;li&gt;By default any Java file that ends with: Test*.java *Test.java, *Tests.java, *TestCase.java.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now may come the &lt;strong&gt;AHA!&lt;/strong&gt; moment, "so this is why my shiny JUnit test was not executed, because I named it UserServiceT or UserServiceTE".&lt;/p&gt;

&lt;p&gt;Yes! But you can configure it to include new patterns or specific files can be put into the include section.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why isn't Surefire plugin good for running integration tests?
&lt;/h3&gt;

&lt;p&gt;If we check the default lifecycle, we will see a list of the available phases: &lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#default-lifecycle" rel="noopener noreferrer"&gt;
      maven.apache.org
    &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6lu0p0pq53ixcnk17d0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6lu0p0pq53ixcnk17d0.png" alt="Maven Default lifecycle"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's check the &lt;code&gt;test&lt;/code&gt; phase again. Before this phase we can only see the &lt;code&gt;test-compile&lt;/code&gt; which is necessary to compile the test classes, we definitely see some other phases, but they are not that "interesting" for us now.&lt;/p&gt;

&lt;p&gt;After that we see no "test" related phases, but the &lt;code&gt;integration-test&lt;/code&gt; phase, which is not associated with the Surefire plugin by default.&lt;/p&gt;

&lt;p&gt;What if we want to run integration tests, that would require different environmental setups, like running a &lt;strong&gt;docker-compose.yml&lt;/strong&gt; file before running any integration test, and stopping the started dependencies when the integration tests finished?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maven Surefire is not created for running integration tests, this is why it is not picking up test classes having the IT,ITCase postfix in their names, for that Maven Failsafe plugin should be used!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;📝 One small note here: You definitely can configure the Surefire plugin to handle the test classes ending with IT,ITCase, but it is just not meant to be used with them. On the other hand, integration tests also can be named as simple Test,Tests,TestCase, but they are different, please do not mix your unit and integration tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maven Failsafe Plugin
&lt;/h3&gt;

&lt;p&gt;Let me quote the following from the Failsafe plugin's documentation:&lt;/p&gt;

&lt;p&gt;"The Failsafe Plugin is designed to run integration tests while the Surefire Plugin is designed to run unit tests. The name (failsafe) was chosen both because it is a synonym of surefire and because it implies that when it fails, it does so in a safe way.&lt;/p&gt;

&lt;p&gt;The Maven lifecycle has four phases for running integration tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;pre-integration-test&lt;/strong&gt; for setting up the integration test environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;integration-test&lt;/strong&gt; for running the integration tests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;post-integration-test&lt;/strong&gt; for tearing down the integration test environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;verify&lt;/strong&gt; for checking the results of the integration tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you use the Surefire Plugin for running tests, then when you have a test failure, the build will stop at the integration-test phase and your integration test environment will not have been torn down correctly.&lt;/p&gt;

&lt;p&gt;The Failsafe Plugin is used during the integration-test and verify phases of the build lifecycle to execute the integration tests of an application. The Failsafe Plugin will not fail the build during the integration-test phase, thus enabling the post-integration-test phase to execute." - Source: &lt;a href="https://maven.apache.org/surefire/maven-failsafe-plugin/" rel="noopener noreferrer"&gt;https://maven.apache.org/surefire/maven-failsafe-plugin/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can not be described better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For unit test: Use &lt;strong&gt;Surefire&lt;/strong&gt; !&lt;/li&gt;
&lt;li&gt;For integration tests: Use &lt;strong&gt;Failsafe&lt;/strong&gt; ! &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How does Maven Failsafe plugin work?
&lt;/h3&gt;

&lt;p&gt;It is "almost" doing the same as the &lt;strong&gt;Surefire&lt;/strong&gt; plugin, it executes test from a specific directory and with a specific filename pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test classes directory: &lt;a href="https://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#testclassesdirectory" rel="noopener noreferrer"&gt;https://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#testclassesdirectory&lt;/a&gt; 

&lt;ul&gt;
&lt;li&gt;Same as for the &lt;strong&gt;Surefire&lt;/strong&gt;, so the &lt;code&gt;target/test-classes&lt;/code&gt;, the compiled source files are also being compiled by the &lt;strong&gt;Maven Compiler Plugin&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Included classes: &lt;a href="https://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#includes" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#includes" rel="noopener noreferrer"&gt;https://maven.apache.org/surefire/maven-failsafe-plugin/integration-test-mojo.html#includes&lt;/a&gt; 

&lt;ul&gt;
&lt;li&gt;This is where the difference can be seen easily, while the &lt;strong&gt;Surefire&lt;/strong&gt; plugin included java classes ending with Test,Tests,TestCase postfixes, in this case the following patterns are the default: IT*.java, *IT.java, *ITCase.java. - So for example &lt;code&gt;UserServiceIT.java&lt;/code&gt; or &lt;code&gt;CreateUserITCase.java&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The main point here is that by default unit and integration tests must be put into the "same" folder structure, so to the &lt;code&gt;src/tests&lt;/code&gt; folder. There are no &lt;code&gt;src/it&lt;/code&gt; or &lt;code&gt;src/it-test&lt;/code&gt; options by default, but it can changed easily, wait till the end.&lt;/p&gt;




&lt;h3&gt;
  
  
  How to organize tests properly in your Maven project?
&lt;/h3&gt;

&lt;p&gt;We have a few options, I will show you 3 that I'm aware of, and I will try to define the advantages and the disadvantages of the different setups.&lt;/p&gt;

&lt;p&gt;I want to make a note here, our goal is to &lt;strong&gt;not break the package setups&lt;/strong&gt;, so every time we write a unit or integration tests for a class, we would like to mirror the setup of the production and test code packages like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqginvuk0qcjrmmhvc0p3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqginvuk0qcjrmmhvc0p3.png" alt="Production and test code setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So if we have a package like this: &lt;code&gt;org.rodnansol.user&lt;/code&gt; and we have a class in it named &lt;code&gt;UserService&lt;/code&gt; our &lt;code&gt;UserServiceTest&lt;/code&gt; or &lt;code&gt;UserServiceIT&lt;/code&gt; should end up in the &lt;code&gt;org.rodnansol.user&lt;/code&gt; package too.&lt;/p&gt;

&lt;p&gt;There are cases when our integrations tests (because we name them IT) are covering a different level in the level test pyramid, like full end 2 end tests, in those cases it is another topic how the classes are structured, but if you think about it, in those cases, you might not know about the code you are testing, in those cases it can be a blackbox, and it is up to you how you set it up.&lt;/p&gt;

&lt;p&gt;Quick spoiler: In the second option we will break it, but you will see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not forget to set up the Maven Failsafe plugin to run the tests!&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-failsafe-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.0-M8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-integration-test&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Mix unit and integration tests
&lt;/h4&gt;

&lt;p&gt;As its name say, mix the unit and integration tests, just by placing them next to each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcr49fcbud051nn8wl6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffcr49fcbud051nn8wl6z.png" alt="Mixing unit and integration tests"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Advantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Tests can be found easily next to each other.&lt;/li&gt;
&lt;li&gt;Encapsulation should not be broken, so if the &lt;code&gt;UseService&lt;/code&gt; will only be used in the &lt;code&gt;user&lt;/code&gt; package, it can be &lt;strong&gt;package private&lt;/strong&gt;. Just because we are writing a test for a class, it does not mean that the encapsulation should be broken, it is also true for methods, fields, constants in classes. Always work for the narrowest scope, do not extend it just because a test needs something.

&lt;ul&gt;
&lt;li&gt;Yes, if you did not know, visibility in the production and test code are not different, so tests can access package private or protected members of the production code! Use it wisely!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
  
  
  Disadvantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;The unit and integration tests are mixed, it can pollute the code and if the integration test is having different utility classes they may end up next to these classes, and with time and without proper maintenance the setup can be a mess.&lt;/li&gt;
&lt;/ul&gt;


&lt;h4&gt;
  
  
  Separate unit and integration tests on package level
&lt;/h4&gt;

&lt;p&gt;I have seen it on many projects where if we had a package structure like this: &lt;code&gt;org.rodnansol.user&lt;/code&gt; developers introduced a middle package that meant to be used by the integration tests for example: &lt;code&gt;org.rodnansol.it.user&lt;/code&gt; or &lt;code&gt;org.rodnansol.integrationtest.user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2mrd0s3izcwpfguk9j1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft2mrd0s3izcwpfguk9j1.png" alt="Different package for ITs"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Advantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Unit and integration tests are separated.&lt;/li&gt;
&lt;li&gt;Integration test related utilities can be put next to the integration test and they can be marked as package private, to make sure other tests will not use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
  
  
  Disadvantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulation is broken! Not just a little, but way too much!

&lt;ul&gt;
&lt;li&gt;Our UserService class from now can not be package-private.&lt;/li&gt;
&lt;li&gt;None of the UserService methods can be package-private that will be used in the integration-test.&lt;/li&gt;
&lt;li&gt;If we want to play around with some dependency mocking if they reside in the same package as package-private classes, now they must be public to be accessible for the test.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if it seems tempting to use this kind of setup, please think about the consequences in the production code. Visibility modifiers are created to be used wisely and properly. Just because a test needs to test a method, it can not be a reason to change its visibility modifier! I would call it as a code smell!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Please think twice before this option is going to be used.&lt;/strong&gt;&lt;/p&gt;


&lt;h4&gt;
  
  
  Separate unit and integration tests on root folder level
&lt;/h4&gt;

&lt;p&gt;From my point of view probably the "cleanest" solution! Separating the unit and integration tests on "root" folder level, like on the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2riffsk63yq1nzqhzaj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2riffsk63yq1nzqhzaj.png" alt="Separate unit and ITs on folder level"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main problem with this setup is that it does not work without some configuration. The &lt;strong&gt;Maven Compiler Plugin&lt;/strong&gt; compiles the Java classes in the following directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src/main/java&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/test/java&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if we want to introduce a third folder we should be making changes even to the &lt;strong&gt;Maven Compiler Plugin,&lt;/strong&gt; or we have to trick the system, and we have to make sure even if the &lt;strong&gt;Maven Compiler Plugin&lt;/strong&gt;'s default configuration is not overwritten our Java classes and resource files are compiled and can be used by the &lt;strong&gt;Maven Failsafe Plugin&lt;/strong&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  How to set it up?
&lt;/h5&gt;

&lt;p&gt;First of all create the following folder stucture for your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;project-root-level&amp;gt;&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;src&lt;/li&gt;
&lt;li&gt;it

&lt;ul&gt;
&lt;li&gt;java&lt;/li&gt;
&lt;li&gt;resources&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;main

&lt;ul&gt;
&lt;li&gt;java&lt;/li&gt;
&lt;li&gt;resources&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;test

&lt;ul&gt;
&lt;li&gt;java&lt;/li&gt;
&lt;li&gt;resources&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h6&gt;
  
  
  Maven Compiler Plugin Way
&lt;/h6&gt;

&lt;p&gt;Overwrite the default configuration of the &lt;strong&gt;maven-compiler-plugin&lt;/strong&gt; and for the &lt;code&gt;test-compile&lt;/code&gt; phase overwrite the &lt;code&gt;compileSourceRoots&lt;/code&gt; configuration values and add the following entries to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;compileSourceRoot&amp;gt;src/test/java&amp;lt;/compileSourceRoot&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;compileSourceRoot&amp;gt;src/it/java&amp;lt;/compileSourceRoot&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make sure any test related resources, that is not a Java file, is copied to the &lt;code&gt;target/test-classes&lt;/code&gt; folder, we must configure the &lt;code&gt;&amp;lt;testResources&amp;gt;&lt;/code&gt; tag too, to include the resources from the &lt;code&gt;src/it/resources&lt;/code&gt; folder too. It is done by the &lt;strong&gt;Maven Resources Plugin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Check out the full plugin configuration:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;testResources&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testResource&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/it/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testResource&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testResource&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/test/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/testResource&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/testResources&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-compiler-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.11.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-testCompile&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;test-compile&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;testCompile&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;compileSourceRoots&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;compileSourceRoot&amp;gt;&lt;/span&gt;src/test/java&lt;span class="nt"&gt;&amp;lt;/compileSourceRoot&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;compileSourceRoot&amp;gt;&lt;/span&gt;src/it/java&lt;span class="nt"&gt;&amp;lt;/compileSourceRoot&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/compileSourceRoots&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-failsafe-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.0-M8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-integration-test&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h6&gt;
  
  
  build-helper-maven-plugin way
&lt;/h6&gt;

&lt;p&gt;In this case the &lt;strong&gt;maven-compiler-plugin&lt;/strong&gt; should not be overwritten, but a new plugin must be introduced to the whole project, it is called &lt;strong&gt;build-helper-maven-plugin&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The folder setup is the same as before, but in this case with the plugin we hook two goals to the following phases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;generate-test-sources - "generate any test source code for inclusion in compilation." - With this phase binding our classes from the &lt;code&gt;src/it/java&lt;/code&gt; will be compiled during the test-compile phase.&lt;/li&gt;
&lt;li&gt;generate-test-resources - "create resources for testing." - With this phase binding all the integration test related resources files are going to be copied to the &lt;code&gt;target/test-classes&lt;/code&gt; folder.

&lt;ul&gt;
&lt;li&gt;With the &lt;code&gt;&amp;lt;filtering&amp;gt;&lt;/code&gt; option if any of the resource files are containing variable substitutions (${}) maven will filter those values and replace them with values from the &lt;code&gt;pom.xml&lt;/code&gt; - this is optional.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the full plugin configuration:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;build&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;plugins&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.codehaus.mojo&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;build-helper-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;add-integration-test-sources&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;generate-test-sources&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;add-test-source&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;sources&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;source&amp;gt;&lt;/span&gt;src/it/java&lt;span class="nt"&gt;&amp;lt;/source&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/sources&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;add-integration-test-resources&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;generate-test-resources&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;add-test-resource&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;filtering&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/filtering&amp;gt;&lt;/span&gt;
                                &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;src/it/resources&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-failsafe-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.0.0-M8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;default-integration-test&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;integration-test&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/plugins&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/build&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After any of the plugin setups the following command should copy and compile any test sources and resources into the &lt;code&gt;target/test-classes&lt;/code&gt; folder: &lt;code&gt;mvn clean verify&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;verify&lt;/code&gt; phase will trigger the &lt;strong&gt;Maven Failsafe Plugin&lt;/strong&gt;'s &lt;code&gt;integration-test&lt;/code&gt; goal within the &lt;code&gt;integration-test&lt;/code&gt; phase.&lt;/p&gt;

&lt;p&gt;📝 &lt;strong&gt;Small note:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Make sure the files under the &lt;code&gt;src/test&lt;/code&gt; and &lt;code&gt;src/it&lt;/code&gt; are having different names because they will overwrite each other, and it will cause surprises.&lt;/p&gt;

&lt;h5&gt;
  
  
  Advantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Unit and integration tests are separated.&lt;/li&gt;
&lt;li&gt;Integration test related utilities can be put next to the integration test and they can be marked as package private, to make sure other tests will not use it.&lt;/li&gt;
&lt;li&gt;Encapsulation will not be broken, if the packaging is correct, both the unit and integration tests will be able to access the allowed classes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Disadvantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Maven Compiler Plugin&lt;/strong&gt; must be changed OR a 3rd party Maven plugin, named &lt;strong&gt;build-helper-maven-plugin&lt;/strong&gt; must be introduced to help with the necessary setups.&lt;/li&gt;
&lt;/ul&gt;




&lt;h4&gt;
  
  
  Surprise option: New maven module
&lt;/h4&gt;

&lt;p&gt;I will not go into details, but I have already seen a few projects where integration tests were not part of the actual Maven module, but they were in a new module which only contained integration tests.&lt;/p&gt;

&lt;h5&gt;
  
  
  Advantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Unit and integration tests are separated.&lt;/li&gt;
&lt;li&gt;Integration test related utilities can be put next to the integration test and they can be marked as package private, to make sure other tests will not use it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Disadvantages
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;The new maven module must depend on the one it is verifying with the integration tests, so the maven module under test can be built without even verifying its behaviour. You decide if it is an advantage or disadvantage. The whole purpose of doing tests is to make sure an artifact is not being packaged if there are problems with its behaviour.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Wow! That was a long journey, I hope you found it useful and this setup will be utilized in your next project setup 🎉 &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We learnt how Maven works and how it generates and uses its &lt;strong&gt;Effective POM&lt;/strong&gt; to build up its lifecycles.&lt;/li&gt;
&lt;li&gt;We learnt how &lt;strong&gt;Surefire&lt;/strong&gt; and &lt;strong&gt;Failsafe&lt;/strong&gt; plugins work and how they differ.&lt;/li&gt;
&lt;li&gt;We learnt 3 ways to set up our unit and integration tests in detail.&lt;/li&gt;
&lt;li&gt;We learnt a 4th method briefly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm curious what you think about it, if you have made it so far! &lt;/p&gt;

&lt;p&gt;How are you setting up your projects?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do you see similarities?&lt;/li&gt;
&lt;li&gt;What are the problems you are facing with your current setup?&lt;/li&gt;
&lt;li&gt;Will you consider separating your unit and integration tests?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; 

&lt;a href="https://github.com/rodnansol/articles-posts/tree/main/Testing-with-Maven" class="ltag_cta ltag_cta--branded" rel="noopener noreferrer"&gt;Check out the sample project&lt;/a&gt;


&lt;/p&gt;




&lt;h2&gt;
  
  
  Follow Rodnan Sol for more
&lt;/h2&gt;

&lt;p&gt;
&lt;a href="https://twitter.com/rodnansol" rel="noopener noreferrer"&gt;&lt;img alt="Twitter followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Ftwitter%2Ffollow%2Frodnansol%3Flogo%3Dtwitter%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://github.com/rodnansol" rel="noopener noreferrer"&gt;&lt;img alt="GitHub followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Ffollowers%2Frodnansol%3Flabel%3DFollow%2520rodnansol%26logo%3Dgithub%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://dcbadge.vercel.app/api/server/USyh6XUjvP" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdcbadge.vercel.app%2Fapi%2Fserver%2FUSyh6XUjvP"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the author too
&lt;/h2&gt;

&lt;p&gt; 
&lt;a href="https://twitter.com/therealhnk" rel="noopener noreferrer"&gt;&lt;img alt="Twitter followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Ftwitter%2Ffollow%2Ftherealhnk%3Flogo%3Dtwitter%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://github.com/nandorholozsnyak" rel="noopener noreferrer"&gt;&lt;img alt="GitHub followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Ffollowers%2Fnandorholozsnyak%3Flabel%3DFollow%2520nandorholozsnyak%26logo%3Dgithub%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>java</category>
      <category>maven</category>
      <category>testing</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Spring Configuration Property Documenter</title>
      <dc:creator>Nándor Holozsnyák</dc:creator>
      <pubDate>Fri, 10 Mar 2023 10:50:00 +0000</pubDate>
      <link>https://dev.to/rodnan-sol/spring-configuration-property-documenter-3d9p</link>
      <guid>https://dev.to/rodnan-sol/spring-configuration-property-documenter-3d9p</guid>
      <description>&lt;h2&gt;
  
  
  Problems
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Have you ever felt that you have no proper way to oversee a project because it is having a lot of customizable properties, but they are not documented, and you do not know where to start a new feature or bugfix?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you ever felt like you are having too much services, and you do not know how to customize them externally?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you ever wondered is there any way to document your application's properties that you are having in your project?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If for any question your answer is &lt;strong&gt;YES&lt;/strong&gt; then you are at the best place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Configuration Property Documenter
&lt;/h2&gt;

&lt;p&gt;This tool lets you generate informative and useful documentations about the classes annotated with the &lt;code&gt;@ConfigurationProperties&lt;/code&gt; in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  But how?
&lt;/h3&gt;

&lt;p&gt;It is easy, if you are working with Spring Boot, you first need a dependency on your classpath during build time, it is annotation processor that will read your classes and generates a metadata file based on the annotation configuration classes.&lt;/p&gt;

&lt;p&gt;In case of Maven, you should add the following dependency:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-configuration-processor&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;optional&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/optional&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After a &lt;code&gt;mvn package&lt;/code&gt; the following file should appear in your &lt;code&gt;target&lt;/code&gt; folder's &lt;code&gt;META-INF&lt;/code&gt; folder: &lt;code&gt;spring-configuration-metadata.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is a simple JSON file, but it contains information about your configuration properties.&lt;/p&gt;

&lt;p&gt;Let's see an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"this.is.my"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * This is my variable.
     */&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Deprecated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;since&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Since you are a pilot"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;anotherVariable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"with default value"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * A duration.
     */&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofDays&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt; &lt;span class="n"&gt;instant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofEpochSecond&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1995&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt; &lt;span class="n"&gt;dateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LocalDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1995&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Getters &amp;amp; Setters&lt;/span&gt;

    &lt;span class="nd"&gt;@DeprecatedConfigurationProperty&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Because it is deprecated"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replacement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"instant"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt; &lt;span class="nf"&gt;getDuration&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Generated &lt;code&gt;spring-configuration-metadata.json&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.date"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.time.LocalDate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.date-time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.time.LocalDateTime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.instant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.time.Instant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.variable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.lang.String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This is my variable."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.another-variable"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.lang.String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"deprecated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"deprecation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this.is.my.duration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"java.time.Duration"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A duration."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sourceType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"org.rodnansol.MyProperties"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"deprecated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"deprecation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Because it is deprecated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"replacement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"instant"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Okay, but what's next?
&lt;/h3&gt;

&lt;p&gt;We built you a tool that can use this JSON file and can generate a documentation from it in the following formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Markdown&lt;/li&gt;
&lt;li&gt;AsciiDoc&lt;/li&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;XML - in case of an XSLT transformation and with XSD support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You name it&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find it &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  What can it do?
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Reading one or multiple metadata files
&lt;/h4&gt;

&lt;p&gt;After it reads your metadata JSON file, a document will be created in the specified format.&lt;/p&gt;

&lt;p&gt;Multiple JSON metadata files can be specified before the process, multi-module projects can also utilize it to have only one document where all the properties are available from the different modules.&lt;/p&gt;

&lt;p&gt;If the metadata file is in a JAR file, it is not a problem, the tool can read it from the JAR file.&lt;/p&gt;
&lt;h4&gt;
  
  
  Aggregating more metadata files
&lt;/h4&gt;

&lt;p&gt;If you are working in a multi-module environment, you may have multiple metadata files, but you do not have to worry, single documentations and aggregated documentations also can be produced.&lt;/p&gt;
&lt;h4&gt;
  
  
  Default templates and customization
&lt;/h4&gt;

&lt;p&gt;The tool provides you a default template that is written with &lt;strong&gt;Handlebars&lt;/strong&gt;, but it is also prepared to support custom templates as well.&lt;/p&gt;

&lt;p&gt;By default, the &lt;strong&gt;Handlebars&lt;/strong&gt; templating engine is supported, but you have the ability to use your own templating engine, but you have to write an extension for it.&lt;/p&gt;

&lt;p&gt;Check out the documentation &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/docs/template-customization.adoc#custom-template-compiler" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Excluding and including groups and properties
&lt;/h4&gt;

&lt;p&gt;As the tool lets you read and use metadata files from JAR files as well, you are able to extract information from the official Spring Boot JARs and you can put this into your final documenatation.&lt;/p&gt;

&lt;p&gt;Sometimes these files are big and you may want to select specific groups and/or keys to be rendered or not rendered into the final output.&lt;/p&gt;

&lt;p&gt;Exclusion and inclusion lists are also supported.&lt;/p&gt;

&lt;p&gt;Please check the following samples &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/samples/multi-module/multi-module-docs/pom.xml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to use the tool?
&lt;/h3&gt;

&lt;p&gt;The core functionalities are built with Java 11 and these functionalities are available through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/docs/maven-plugin.adoc" rel="noopener noreferrer"&gt;Maven plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/docs/usage-jbang.adoc" rel="noopener noreferrer"&gt;JBang script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/docs/gradle-plugin.adoc" rel="noopener noreferrer"&gt;Gradle plugin (Coming soon)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Maven usage
&lt;/h3&gt;

&lt;p&gt;Just add the following plugin to your &lt;code&gt;pom.xml&lt;/code&gt; and you are ready to go.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;


&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.rodnansol&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-configuration-property-documenter-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${final-version}&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;generate-adoc&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;phase&amp;gt;&lt;/span&gt;process-classes&lt;span class="nt"&gt;&amp;lt;/phase&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;generate-property-document&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;type&amp;gt;&lt;/span&gt;ADOC&lt;span class="nt"&gt;&amp;lt;/type&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fmaven-central%2Fv%2Forg.rodnansol%2Fspring-configuration-property-documenter%3Flabel%3DThe%2520final%2520version%2520is%2520%26style%3Dfor-the-badge" class="article-body-image-wrapper"&gt;&lt;img alt="Final version" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fmaven-central%2Fv%2Forg.rodnansol%2Fspring-configuration-property-documenter%3Flabel%3DThe%2520final%2520version%2520is%2520%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Check the available Maven goals &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/blob/master/docs/maven-plugin.adoc#available-goals-and-config" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Template customization
&lt;/h3&gt;

&lt;p&gt;The templates can be customized if the default one is not fitting your requirements, please read the docs about that &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/tree/master/samples" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1cobryz1gzvkmfnu27b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo1cobryz1gzvkmfnu27b.png" alt="AsciiDoc Example"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft11190vbiz0bnehyeeav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft11190vbiz0bnehyeeav.png" alt="AsciiDoc Example 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Checkout the samples &amp;amp; docs
&lt;/h3&gt;

&lt;p&gt;Feel free to check out the samples and documentation because it will give a wider knowledge about the how-tos.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/tree/master/samples" rel="noopener noreferrer"&gt;Samples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/tree/master/docs" rel="noopener noreferrer"&gt;Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Are you using Spring Boot with Quarkus?
&lt;/h3&gt;

&lt;p&gt;If yes, do not worry, we got you covered, check out this &lt;a href="https://github.com/rodnansol/spring-configuration-property-documenter/tree/master/samples/quarkus-spring-boot-single-module" rel="noopener noreferrer"&gt;sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow Rodnan Sol for more
&lt;/h2&gt;

&lt;p&gt;
&lt;a href="https://twitter.com/rodnansol" rel="noopener noreferrer"&gt;&lt;img alt="Twitter followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Ftwitter%2Ffollow%2Frodnansol%3Flogo%3Dtwitter%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://github.com/rodnansol" rel="noopener noreferrer"&gt;&lt;img alt="GitHub followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Ffollowers%2Frodnansol%3Flabel%3DFollow%2520rodnansol%26logo%3Dgithub%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://dcbadge.vercel.app/api/server/USyh6XUjvP" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdcbadge.vercel.app%2Fapi%2Fserver%2FUSyh6XUjvP"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the author too
&lt;/h2&gt;

&lt;p&gt; 
&lt;a href="https://twitter.com/therealhnk" rel="noopener noreferrer"&gt;&lt;img alt="Twitter followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Ftwitter%2Ffollow%2Ftherealhnk%3Flogo%3Dtwitter%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;a href="https://github.com/nandorholozsnyak" rel="noopener noreferrer"&gt;&lt;img alt="GitHub followers" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimg.shields.io%2Fgithub%2Ffollowers%2Fnandorholozsnyak%3Flabel%3DFollow%2520nandorholozsnyak%26logo%3Dgithub%26style%3Dfor-the-badge"&gt;&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>asciidoc</category>
      <category>html</category>
      <category>markdown</category>
    </item>
  </channel>
</rss>
