Skip to content

Add JaCoCo coverage enforcement and achieve 100% line coverage#6

Open
devin-ai-integration[bot] wants to merge 1 commit into
devin/1775585131-java-springboot-todo-appfrom
devin/1776279285-unit-test-coverage
Open

Add JaCoCo coverage enforcement and achieve 100% line coverage#6
devin-ai-integration[bot] wants to merge 1 commit into
devin/1775585131-java-springboot-todo-appfrom
devin/1776279285-unit-test-coverage

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 15, 2026

Summary

Adds the JaCoCo Maven plugin with enforcement thresholds (≥95% line, ≥85% branch) and writes new unit tests to close all coverage gaps. Test count goes from 63 → 106, and line coverage goes from ~71% → 100%.

Build config:

  • JaCoCo plugin (0.8.11) added to pom.xml with prepare-agent, report (on test phase), and check (on verify phase) executions.
  • Coverage gates: 95% line, 85% branch at BUNDLE level.

New test files (9):

  • TodoViewControllerTest — 14 tests for the Thymeleaf view controller (was completely untested; biggest coverage gap at 61 missed lines)
  • TodoResponseTestfromEntity() branch coverage: overdue logic for PENDING/COMPLETED/CANCELLED/future due dates, null timestamps
  • TodoTest — model lifecycle: onCreate, onUpdate (completedAt set/clear/preserve branches), toString
  • DataInitializerTestCommandLineRunner with empty vs. pre-populated repository
  • GlobalExceptionHandlerTest — direct unit test for handleTodoNotFound and handleGenericException
  • TodoNotFoundExceptionTest, TodoRequestTest, PriorityTest, TodoStatusTest — small gap-closing tests
  • TodoApplicationTest — exercises main() entry point

Extended existing file:

  • TodoServiceTest — added getTodosByStatus and getTodosByPriority tests (last 4 uncovered lines)

Final coverage: 100% lines (369/369), ~96% branches (55/57). The 2 missed branches are instruction-level in TodoService (not line-level).

Review & Testing Checklist for Human

  • Verify JaCoCo check phase matches CI pipeline — the check goal runs during verify, not test. If CI only runs mvn test, the coverage gate won't enforce. Confirm mvn verify (or equivalent) is what CI executes.
  • Review TodoApplicationTest — it calls TodoApplication.main(...) inside a @SpringBootTest, which boots the Spring context twice in the same JVM. This works but is unconventional; consider whether the existing TodoApplicationTests.contextLoads() already provides sufficient coverage and whether this test adds maintenance cost.
  • Assess coverage-only tests for maintenance burden — some tests (enum value counts, getter/setter round-trips, assertThat(true).isTrue()) exist purely to hit coverage thresholds. Decide if these are worth keeping or if they'll become noise during refactors.

Suggested test plan: Run ./mvnw clean verify locally and confirm the build passes with JaCoCo check. Open target/site/jacoco/index.html to inspect per-class coverage.

Notes

  • No production code was modified.
  • The 95% line / 85% branch thresholds can be adjusted in the pom.xml JaCoCo check configuration if the team prefers different gates.

Link to Devin session: https://app.devin.ai/sessions/fc87ba68757648cd85137fd50a01f0e2
Requested by: @clivingston-cognition


Open with Devin

- Configure JaCoCo Maven plugin with 95% line / 85% branch coverage gates
- Add TodoViewControllerTest (14 tests covering all view endpoints)
- Add TodoTest (model lifecycle: onCreate, onUpdate, toString, getters/setters)
- Add PriorityTest and TodoStatusTest (enum displayName coverage)
- Add DataInitializerTest (sample data seeding with empty/non-empty repo)
- Add GlobalExceptionHandlerTest (404, 500 error handling)
- Add TodoNotFoundExceptionTest (exception id storage)
- Add TodoResponseTest (fromEntity with all branch paths including overdue logic)
- Add TodoRequestTest (constructors and getters/setters)
- Add TodoApplicationTest (main method entry point)
- Extend TodoServiceTest with getTodosByStatus and getTodosByPriority tests

Coverage: 100% lines (369/369), 96.4% branches (55/57)
Tests: 106 total (up from 63)
Co-Authored-By: Chris Livingston <chris.livingston@cognition.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 4 additional findings in Devin Review.

Open in Devin Review

Comment on lines +17 to +21
void mainMethodStartsContext() {
// Calling main with the test profile active exercises the main() entry point.
TodoApplication.main(new String[]{"--spring.profiles.active=test"});
assertThat(true).isTrue();
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 TodoApplicationTest.main() starts a second unmanaged ApplicationContext that leaks resources and binds port 8080

The mainMethodStartsContext test calls TodoApplication.main() which invokes SpringApplication.run() (TodoApplication.java:10), starting a second, fully real Spring ApplicationContext with an embedded Tomcat web server. The @SpringBootTest annotation already starts one context (with WebEnvironment.MOCK, which doesn't bind a port). The main() call starts a second context that will attempt to bind to port 8080 (the default from application.properties:3, not overridden by application-test.properties). This second context is never captured or closed, so it leaks for the rest of the test JVM's lifetime. If port 8080 is already in use (e.g., in a CI environment or when running alongside a local dev server), the test will fail with a BindException.

Prompt for agents
The test calls TodoApplication.main() inside a @SpringBootTest, which creates a second, unmanaged ApplicationContext that binds to port 8080 and is never closed. There are two common fixes:

1. Remove @SpringBootTest and just verify that main() can be called without throwing. To avoid port conflicts, pass --server.port=0 along with --spring.profiles.active=test, and capture the returned context to close it in a finally/try-with-resources block.

2. If the goal is just to get coverage on the main() entry point, use a simpler approach: invoke main() in a non-SpringBootTest context, capture the ConfigurableApplicationContext returned by SpringApplication.run (which main currently discards), and close it. Alternatively, just rely on the existing TodoApplicationTests.contextLoads() test which already verifies the context loads.

File: src/test/java/com/example/todo/TodoApplicationTest.java
Related: src/main/java/com/example/todo/TodoApplication.java (the main method)
Related: src/main/resources/application.properties (server.port=8080)
Related: src/test/java/com/example/todo/TodoApplicationTests.java (existing context load test)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant