How do you set up JaCoCo to measure code coverage in a Maven build, and what does the prepare-agent goal actually do?
answer
- prepare-agent sets argLine
- javaagent attaches to test JVM
- jacoco.exec output
- Surefire/Failsafe read ${argLine}
- @{argLine} avoids clobber
basics
~10 sAdd the jacoco-maven-plugin and bind its prepare-agent goal. prepare-agent sets a property (argLine) that adds the JaCoCo Java agent to the JVM running your tests, so it records which lines execute.
solid answer
~40 sYou add jacoco-maven-plugin to the build and bind the prepare-agent goal (usually to the initialize/early phase via the default execution). prepare-agent does not run tests itself; it configures the JaCoCo Java agent and exposes its JVM options in a Maven property named argLine by default. Surefire/Failsafe pick up ${argLine} and prepend it to the test JVM command line, so the agent instruments classes on the fly and writes execution data to target/jacoco.exec. The key gotcha: if you also set argLine manually (e.g. for -Xmx), you must include @{argLine} or set it via a property so you don't clobber JaCoCo's value. Then bind the report goal (typically to the test/verify phase) to turn jacoco.exec into HTML/XML.
code
xml · 16 lines<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.12</version>
<executions>
<execution>
<id>jacoco-prepare</id>
<goals><goal>prepare-agent</goal></goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>test</phase>
<goals><goal>report</goal></goals>
</execution>
</executions>
</plugin>go deeper
Knows you add jacoco-maven-plugin and bind prepare-agent + report to get a coverage report.
Understands prepare-agent populates the argLine property that Surefire/Failsafe consume to attach the agent.
Diagnoses empty-coverage problems from argLine clobbering and uses @{argLine} or a custom propertyName.
Standardizes coverage wiring across many repos via a parent/BOM, sets propertyName conventions and avoids per-module argLine hacks.
## What code coverage is Code coverage measures which lines/branches of your source code were actually executed while your tests ran. JaCoCo (Java Code Coverage) is the de-facto tool; the `jacoco-maven-plugin` integrates it into Maven. ## How JaCoCo collects data JaCoCo works as a **Java agent** — a `-javaagent:...` JVM argument that instruments bytecode as classes load and records execution counts. To get coverage you must inject that agent into the JVM that runs your tests. ## The prepare-agent goal The `prepare-agent` goal does NOT run tests. Its job is to compute the correct `-javaagent` string and store it in a Maven property. By default that property is named **`argLine`**. Why `argLine`? Because Maven Surefire (unit tests) and Failsafe (integration tests) read a configuration property called `argLine` and prepend it to the forked test JVM's command line. So by writing into `argLine`, JaCoCo transparently attaches itself to the test JVM. The agent writes raw execution data to **`target/jacoco.exec`** by default. ## Wiring it up ```xml <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.12</version> <executions> <execution> <id>prepare-agent</id> <goals><goal>prepare-agent</goal></goals> </execution> <execution> <id>report</id> <phase>test</phase> <goals><goal>report</goal></goals> </execution> </executions> </plugin> ``` The `prepare-agent` execution binds by default to the **initialize** phase, so it runs before tests. ## The argLine clobbering trap If you set `argLine` yourself in Surefire/Failsafe config (e.g. `-Xmx512m`), you overwrite JaCoCo's value and coverage silently becomes empty. Fix by referencing the late-evaluated property: ```xml <configuration> <argLine>@{argLine} -Xmx512m</argLine> </configuration> ``` The `@{...}` syntax forces Surefire to resolve the property late, after prepare-agent has set it. Alternatively, point JaCoCo at a different property via `<propertyName>surefireArgLine</propertyName>` and reference that. ## Output - `target/jacoco.exec` — binary execution data - `target/site/jacoco/` — HTML report (after the `report` goal)
- Your coverage report is empty (0%) even though tests pass. What's the most likely cause?Something overwrote the JaCoCo argLine — e.g. a hardcoded <argLine> in Surefire config without @{argLine}, so the agent never attached. Also check forkCount/tests actually ran.
- What property does prepare-agent write into and why that name?By default the 'argLine' property, because Surefire and Failsafe automatically prepend ${argLine} to the forked test JVM command line.
prepare-agent is like clipping a fitness tracker onto the JVM before it goes for its run — it doesn't run, it just makes sure the tracker is recording.
saying these in an interview costs you the question
- Saying prepare-agent runs the tests
- Thinking JaCoCo statically modifies source/class files on disk
- Not knowing about the argLine clobbering problem