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”?>
Playground pom.xml:
<?xml version=”1.0” encoding=”UTF-8”?>
PlaygroundUtils pom.xml:
<?xml version=”1.0” encoding=”UTF-8”?>
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.