{"id":844,"date":"2022-09-18T00:01:04","date_gmt":"2022-09-18T00:01:04","guid":{"rendered":"https:\/\/choudhury.com\/blog\/?p=844"},"modified":"2022-09-18T00:01:07","modified_gmt":"2022-09-18T00:01:07","slug":"using-jacoco-merge-goal-to-report-coverage-in-multi-module-projects","status":"publish","type":"post","link":"https:\/\/choudhury.com\/blog\/2022\/09\/18\/using-jacoco-merge-goal-to-report-coverage-in-multi-module-projects\/","title":{"rendered":"Using JaCoCo merge goal to report coverage in multi-module projects"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p><a href=\"https:\/\/github.com\/muminc\/jacoco-merge\" data-type=\"URL\">This Example github project<\/a> shows how  jacoco:merge goal can be used to merge all the exec files<\/p>\n\n\n\n<p>In this example we two projects.\u00a0 <strong>project1<\/strong>\u00a0and\u00a0<strong>project2<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>project1 has 2 classes : Example1 and Example2. It also has 1 unit test to fully cover Example1<\/li><li>project2 has only unit test. The unit test fully covers Example2 from project1<\/li><\/ul>\n\n\n\n<p>As project1 is not covering Example2, jacoco will report 0% coverage for Example2<\/p>\n\n\n\n<p>Firstly, to show that JaCoCo will show 0% coverage for Example2 class in project1 run these commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">mvn clean verify<\/div><\/div>\n\n<\/pre>\n\n\n\n<p>then run <\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">mvn jacoco:report<\/div><\/div>\n\n<\/pre>\n\n\n\n<p>if you go into folder<br><br>project1\/target\/site\/jacoco\/project1 you&#8217;ll the reports produced by jacoco<br><br>The report shows class Example1 has 100% coverage whilst Example2 (which is covered by project2) has 0% coverage<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"239\" src=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1024x239.png\" alt=\"\" class=\"wp-image-845\" srcset=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1024x239.png 1024w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-300x70.png 300w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-768x179.png 768w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image.png 1081w\" sizes=\"auto, (max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/a><\/figure>\n\n\n\n<p><strong>Using merge goal to get JaCoCo to report on coverage provided by other projects<\/strong><\/p>\n\n\n\n<p>For the above example, we want to show Example2 is fully covered  (as coverage was provided by project2)<\/p>\n\n\n\n<p>To get jacoco to report coverage provided by other projects. We need to merge all the jacoco.exec files we have<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>project1 jacoco exec is under project1\/target\/jacoco.exec<\/li><li>project2 jacoco exec is under project2\/target\/jacoco.exec<\/li><\/ul>\n\n\n\n<p>Merge the jacoco.exec from project 1 and project 2 to make a merged jacoco.exec The merged jacoco.exec file will show we have 100% coverage for Example2 class. We will then configure the reporting goal to use this merged exec file.<\/p>\n\n\n\n<h6 class=\"wp-block-heading\">Step 1<\/h6>\n\n\n\n<p>We want to copy all the jacoco.exec file into the top level folder target folder (we may also need to create the target folder)<\/p>\n\n\n\n<p>we need to copy all jacoco.exec we have into\u00a0the top-level target folder, but so that they don&#8217;t overwrite each other, we need to give them unique names, for this we will use merge goal (or you can use copy script for this step)<\/p>\n\n\n\n<p>Note:  jacoco:merge goal requires fileSets\u00a0config to be present see :\u00a0<a href=\"https:\/\/www.eclemma.org\/jacoco\/trunk\/doc\/merge-mojo.html\">merge goal documentation<\/a><\/p>\n\n\n\n<p>We will add this to our the jacoco plugin configuration (so that we can use the merge goal)<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;fileSets>\r\n  &lt;fileSet>\r\n    &lt;directory>${project.build.directory}&lt;\/directory>\r\n    &lt;includes>\r\n      &lt;include>*.exec&lt;\/include>\r\n    &lt;\/includes>\r\n  &lt;\/fileSet>\r\n&lt;\/fileSets><\/pre>\n\n\n\n<p>as mentioned, the file(s) when written to the top level, we don&#8217;t want them to overwrite to each other, so we give them file name :  \u00a0\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">${project.artifactId}.exec<\/div><\/div>\n\n<\/p>\n\n\n\n<p>E.g. on Windows if the project level folder was : c:\/temp\/jacoco-merge<\/p>\n\n\n\n<p>You would run this (making sure that c:\/temp\/jacoco-merge\/target) exists first<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">mvn jacoco:merge -Djacoco.destFile=c:\/temp\/jacoco-merge\/target\/${project.artifactId}.exec<\/div><\/div>\n\n<\/pre>\n\n\n\n<p>End result should look like this (strictly speaking, you could use copy commands to achieve this instead)<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"825\" height=\"198\" src=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1.png\" alt=\"\" class=\"wp-image-846\" srcset=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1.png 825w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1-300x72.png 300w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-1-768x184.png 768w\" sizes=\"auto, (max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/a><\/figure>\n\n\n\n<h6 class=\"wp-block-heading\">Step 2<\/h6>\n\n\n\n<p>Now that we have all the exec files (project1.exec and project2.exec) in one folder, we need to merge these 2 files to produce merged jacoco.exec file<\/p>\n\n\n\n<p>For this, we run this command. NOTE: Since all the files are all in the top level folder, we only need to execute merge goal at the top level folder only so we use flag -N\u00a0to not recurse this merge goal in the child projects.<\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">mvn -N jacoco:merge<\/div><\/div>\n\n<\/pre>\n\n\n\n<p>Result of above<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"990\" height=\"293\" src=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-2.png\" alt=\"\" class=\"wp-image-847\" srcset=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-2.png 990w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-2-300x89.png 300w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-2-768x227.png 768w\" sizes=\"auto, (max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/a><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3<\/h4>\n\n\n\n<p>Now that we have the merged exec file produced in above step. What we want to do is run the report goal (to generate the html reports) but instead the of using default jacoco.dataFile value (${project.build.directory}\/jacoco.exec) we will configure jacoco.dataFile to instead use the merged jacoco exe file<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre class=\"wp-block-code\">\n\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">mvn jacoco:report -Djacoco.dataFile=C:\\temp\\jacoco-merge\\target\\jacoco.exec<\/div><\/div>\n\n<\/pre>\n\n\n\n<p>Now if we look again in project1\/target\/site\/jacoco\/project1  we can see it shows both Example1 and Example2 have 100% coverage<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1025\" height=\"247\" src=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-3.png\" alt=\"\" class=\"wp-image-848\" srcset=\"https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-3.png 1025w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-3-300x72.png 300w, https:\/\/choudhury.com\/blog\/wp-content\/uploads\/2022\/09\/image-3-768x185.png 768w\" sizes=\"auto, (max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/a><\/figure>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This Example github project shows how jacoco:merge goal can be used to merge all the exec files In this example we two projects.\u00a0 project1\u00a0and\u00a0project2 project1 has 2 classes : Example1 and Example2. It also has 1 unit test to fully cover Example1 project2 has only unit test. The unit test fully covers Example2 from project1 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/choudhury.com\/blog\/2022\/09\/18\/using-jacoco-merge-goal-to-report-coverage-in-multi-module-projects\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Using JaCoCo merge goal to report coverage in multi-module projects&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6,3,9,12],"tags":[24],"class_list":["post-844","post","type-post","status-publish","format-standard","hentry","category-code-quality","category-java","category-maven","category-testing","tag-code-coverage"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/posts\/844","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/comments?post=844"}],"version-history":[{"count":9,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/posts\/844\/revisions"}],"predecessor-version":[{"id":858,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/posts\/844\/revisions\/858"}],"wp:attachment":[{"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/media?parent=844"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/categories?post=844"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/choudhury.com\/blog\/wp-json\/wp\/v2\/tags?post=844"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}