lzwjava@Zhiweis-MacBook-Air-1255 playground-server % tree . . ├── AGENTS.md ├── Dockerfile ├── LICENSE ├── PYTHON_COVERAGE.md ├── PlaygroundUtils │   ├── pom.xml │   ├── src │   │   └── main │   │   └── java │   │   └── org │   │   └── lzw │   │   ├── PlaygroundUtils.java │   │   └── SystemUtils.java │   └── target │   ├── PlaygroundUtils-1.0.jar │   ├── classes │   │   └── org │   │   └── lzw │   │   ├── PlaygroundUtils.class │   │   └── SystemUtils.class │   ├── generated-sources │   │   └── annotations │   ├── maven-archiver │   │   └── pom.properties │   └── maven-status │   └── maven-compiler-plugin │   └── compile │   └── default-compile │   ├── createdFiles.lst │   └── inputFiles.lst ├── PlaygroundWeb │   ├── pom.xml │   ├── src │   │   ├── main │   │   │   ├── java │   │   │   │   └── org │   │   │   │   └── lzw │   │   │   │   ├── HelloController.java │   │   │   │   ├── MainController.java │   │   │   │   └── config │   │   │   │   ├── RootConfig.java │   │   │   │   └── WebConfig.java │   │   │   ├── resources │   │   │   │   ├── logback.xml │   │   │   │   └── static │   │   │   │   └── index.html │   │   │   └── webapp │   │   │   └── WEB-INF │   │   │   └── web.xml │   │   └── test │   │   └── java │   │   └── HelloControllerTest.java │   └── target │   ├── PlaygroundWeb-1.0 │   │   ├── META-INF │   │   └── WEB-INF │   │   ├── classes │   │   │   ├── logback.xml │   │   │   ├── org │   │   │   │   └── lzw │   │   │   │   ├── AspectJConfig.class │   │   │   │   ├── DebugAspect.class │   │   │   │   ├── HelloController.class │   │   │   │   ├── MainController.class │   │   │   │   └── config │   │   │   │   ├── RootConfig.class │   │   │   │   └── WebConfig.class │   │   │   └── static │   │   │   └── index.html │   │   ├── lib │   │   │   ├── PlaygroundUtils-1.0.jar │   │   │   ├── commons-lang3-3.17.0.jar │   │   │   ├── jackson-annotations-2.13.1.jar │   │   │   ├── jackson-core-2.13.1.jar │   │   │   ├── jackson-databind-2.13.1.jar │   │   │   ├── logback-classic-1.2.13.jar │   │   │   ├── logback-core-1.2.13.jar │   │   │   ├── slf4j-api-1.7.36.jar │   │   │   ├── spring-aop-5.3.39.jar │   │   │   ├── spring-beans-5.3.39.jar │   │   │   ├── spring-context-5.3.39.jar │   │   │   ├── spring-core-5.3.39.jar │   │   │   ├── spring-expression-5.3.39.jar │   │   │   ├── spring-jcl-5.3.39.jar │   │   │   ├── spring-web-5.3.39.jar │   │   │   └── spring-webmvc-5.3.39.jar │   │   └── web.xml │   ├── PlaygroundWeb-1.0.war │   ├── checkstyle-cachefile │   ├── checkstyle-checker.xml │   ├── checkstyle-result.xml │   ├── checkstyle-suppressions.xml │   ├── classes │   │   ├── logback.xml │   │   ├── org │   │   │   └── lzw │   │   │   ├── HelloController.class │   │   │   ├── MainController.class │   │   │   └── config │   │   │   ├── RootConfig.class │   │   │   └── WebConfig.class │   │   └── static │   │   └── index.html │   ├── generated-sources │   │   └── annotations │   ├── generated-test-sources │   │   └── test-annotations │   ├── jacoco.exec │   ├── maven-archiver │   │   └── pom.properties │   ├── maven-status │   │   └── maven-compiler-plugin │   │   ├── compile │   │   │   └── default-compile │   │   │   ├── createdFiles.lst │   │   │   └── inputFiles.lst │   │   └── testCompile │   │   └── default-testCompile │   │   ├── createdFiles.lst │   │   └── inputFiles.lst │   ├── site │   │   └── jacoco │   │   ├── index.html │   │   ├── jacoco-resources │   │   │   ├── branchfc.gif │   │   │   ├── branchnc.gif │   │   │   ├── branchpc.gif │   │   │   ├── bundle.gif │   │   │   ├── class.gif │   │   │   ├── down.gif │   │   │   ├── greenbar.gif │   │   │   ├── group.gif │   │   │   ├── method.gif │   │   │   ├── package.gif │   │   │   ├── prettify.css │   │   │   ├── prettify.js │   │   │   ├── redbar.gif │   │   │   ├── report.css │   │   │   ├── report.gif │   │   │   ├── session.gif │   │   │   ├── sort.gif │   │   │   ├── sort.js │   │   │   ├── source.gif │   │   │   └── up.gif │   │   ├── jacoco-sessions.html │   │   ├── jacoco.csv │   │   ├── jacoco.xml │   │   ├── org.lzw │   │   │   ├── AspectJConfig.html │   │   │   ├── AspectJConfig.java.html │   │   │   ├── DebugAspect.html │   │   │   ├── DebugAspect.java.html │   │   │   ├── HelloController.html │   │   │   ├── HelloController.java.html │   │   │   ├── MainController.html │   │   │   ├── MainController.java.html │   │   │   ├── index.html │   │   │   └── index.source.html │   │   └── org.lzw.config │   │   ├── RootConfig.html │   │   ├── RootConfig.java.html │   │   ├── WebConfig.html │   │   ├── WebConfig.java.html │   │   ├── index.html │   │   └── index.source.html │   ├── surefire-reports │   │   ├── HelloControllerTest.txt │   │   └── TEST-HelloControllerTest.xml │   └── test-classes │   └── HelloControllerTest.class ├── README.md ├── checks.xml ├── checkstyle-suppressions.xml ├── jetty.log ├── pom.xml ├── scripts │   ├── constants.py │   ├── pdf.py │   ├── test.md │   ├── test.py │   ├── test_server.py │   └── test_server2.py └── tests ├── init.py ├── pycache │   ├── test_hello_endpoint.cpython-313.pyc │   ├── test_jetty.cpython-313.pyc │   └── test_playground_endpoints.cpython-313.pyc ├── test_hello_endpoint.py ├── test_jetty.py └── test_playground_endpoints.py

67 directories, 125 files


pom.xml

<?xml version=”1.0” encoding=”UTF-8”?>

4.0.0 com.lzw PlaygroundLib 1.0 pom PlaygroundLib - Parent 8 8 UTF-8 5.3.39 5.13.1 5.18.0 2.2 1.7.36 1.2.13 4.0.1 3.17.0 2.13.1 2.30.0 3.1.2 9.3 3.5.3 0.8.12 9.4.54.v20240208 3.5.1 3.4.0 PlaygroundUtils PlaygroundWeb org.springframework spring-context ${spring.version} org.springframework spring-web ${spring.version} org.springframework spring-webmvc ${spring.version} org.springframework spring-core ${spring.version} org.junit.jupiter junit-jupiter-api ${junit.jupiter.version} test org.junit.jupiter junit-jupiter-engine ${junit.jupiter.version} test org.mockito mockito-core ${mockito.version} test org.springframework spring-test ${spring.version} test org.hamcrest hamcrest ${hamcrest.version} test org.slf4j slf4j-api ${slf4j.version} ch.qos.logback logback-classic ${logback.version} javax.servlet javax.servlet-api ${servlet.version} provided org.apache.commons commons-lang3 ${commons.lang3.version} com.fasterxml.jackson.core jackson-databind ${jackson.version} com.diffplug.spotless spotless-maven-plugin ${spotless.version} org.apache.maven.plugins maven-checkstyle-plugin ${checkstyle.plugin.version} org.apache.maven.plugins maven-surefire-plugin ${surefire.version} org.jacoco jacoco-maven-plugin ${jacoco.version} org.eclipse.jetty jetty-maven-plugin ${jetty.plugin.version} org.codehaus.mojo exec-maven-plugin ${exec.plugin.version} org.apache.maven.plugins maven-war-plugin ${war.plugin.version}

Playground pom.xml:

<?xml version=”1.0” encoding=”UTF-8”?>

4.0.0 com.lzw PlaygroundLib 1.0 PlaygroundWeb war PlaygroundWeb ${project.build.directory}/jacoco-it.exec false com.lzw PlaygroundUtils ${project.parent.version} org.springframework spring-context org.springframework spring-web org.springframework spring-webmvc org.springframework spring-core org.slf4j slf4j-api ch.qos.logback logback-classic javax.servlet javax.servlet-api provided com.fasterxml.jackson.core jackson-databind org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.mockito mockito-core test org.springframework spring-test test org.hamcrest hamcrest test com.diffplug.spotless spotless-maven-plugin apply compile org.apache.maven.plugins maven-checkstyle-plugin com.puppycrawl.tools checkstyle ${checkstyle.version} ${project.parent.basedir}/checks.xml ${project.parent.basedir}/checkstyle-suppressions.xml true checkstyle-check compile check org.apache.maven.plugins maven-war-plugin true org.apache.maven.plugins maven-surefire-plugin org.jacoco jacoco-maven-plugin prepare-agent prepare-agent report-it verify report ${jacoco.it.exec} ${project.reporting.outputDirectory}/jacoco-it org.eclipse.jetty jetty-maven-plugin start-jetty pre-integration-test start true -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile=${jacoco.it.exec} 8080 127.0.0.1 / 127.0.0.1 8081 stop stop-jetty post-integration-test stop 127.0.0.1 8081 stop 15 org.codehaus.mojo exec-maven-plugin false python-integration-tests integration-test exec python3 ${project.parent.basedir} -m unittest discover tests/ -v

PlaygroundUtils pom.xml:

<?xml version=”1.0” encoding=”UTF-8”?>

4.0.0 com.lzw PlaygroundLib 1.0 PlaygroundUtils jar PlaygroundUtils ${project.build.directory}/jacoco-it.exec true org.apache.commons commons-lang3 org.slf4j slf4j-api com.diffplug.spotless spotless-maven-plugin apply compile org.apache.maven.plugins maven-surefire-plugin

What I want to do is use Python’s unittest to test API endpoints, and then generate a coverage report for a Java Spring project.

What’s special here is that the Python test cases live outside the Java project. That means I need the Maven Exec Plugin to run them.

I also need to start Jetty and keep it running. This is a multi-module project.

At first, I tried using JaCoCo’s aggregate goal.

One issue was that I added the plugins in PlaygroundLib, but PlaygroundLib has no code or tests. Running the JaCoCo plugin there misses the class file structure.

JaCoCo aggregate doesn’t work well in this setup because the coverage is not from unit tests; it’s from external Python integration tests.

So I fell back to generating per-module JaCoCo reports.

I’ve successfully done this for one module before. The flow is fine: run jacoco:prepare-agent, attach the Java agent to the JVM that runs Jetty or WebSphere Liberty, run the Python integration tests, and then generate the coverage report. That part works.

However, there’s a problem with one module. For PlaygroundUtils, there’s no controller, so there’s no integration test when building that module. But its classes do appear in the JaCoCo .exec file. Because of that, I need to run PlaygroundWeb twice—once with the JaCoCo agent for that module’s exec, and once with the agent for PlaygroundUtils.

What do you think overall? What’s a good strategy here? Suppose I have a larger project with ten modules—how should I approach it? If handling all ten at once is too complex, we could start with one or two modules.

Also, JaCoCo is more complicated than tools like Checkstyle or Spotless because it isn’t self-contained: it depends on external Python integration tests, and it requires JaCoCo exec files and JVM agent attachment. That makes things more complex.