feat: implement JUnit5 reporter with Java/Kotlin POJO support and CI/CD#80
feat: implement JUnit5 reporter with Java/Kotlin POJO support and CI/CD#80jsbattig wants to merge 3 commits into
Conversation
Extends TDD Guard to Java ecosystem to enable AI-driven TDD enforcement for Java/Kotlin projects. Discovered during implementation that strict incremental TDD rules conflict with compiled languages' compilation phase, requiring language-specific adaptations. WHY This Change: - Java is a major language lacking TDD Guard support - Claude Code needs TDD enforcement for Java projects - Compiled languages require different TDD workflow than interpreted languages - Educational feedback improves AI agent's Java development patterns - Automated releases reduce manual maintenance burden Core Features: - JUnit5 Platform TestExecutionListener with service provider auto-discovery - Educational feedback: 5 pattern detectors for AI agent learning - Self-detection: Zero overhead when TDD Guard not present - Complete test type support: Standard, @nested, @ParameterizedTest, dynamic - Standard test.json format for consistency across all reporters Java/Kotlin POJO Support (WHY NEEDED): Problem: Strict incremental TDD blocks compilation phase stubs in Java. Tests won't compile without class/method stubs, but TDD Guard blocked stubs without test.json (which only exists after successful compilation). Solution: Research-backed rules from Kent Beck's "Obvious Implementation": - Detects when test file exists (proves test-first intent) - Allows complete POJO structures (fields + constructor + getters) as one unit - Still blocks all business logic without test evidence - Zero impact on other languages (isolated to Java/Kotlin only) Rationale: Java POJOs are structural code (data holders), not behavioral. Community consensus: Testing simple getters/setters is wasteful, they're covered by integration tests. Kent Beck: "If you know what to type and can do it quickly, then do it." Distribution WHY: - GitHub Actions: Automated releases reduce manual errors and save time - Public JAR downloads: No authentication required, easier adoption - GitHub Packages: Option for users who prefer dependency management - Maven support: Extends reach beyond Gradle users Boy Scout Rule WHY: Fixed golangci-lint compatibility because tests were failing. Updated for v1.64+ (current version) to ensure CI/CD works properly. This benefits all contributors, not just this PR. Testing WHY: - 193 tests ensure reporter works correctly across all JUnit5 test types - Manual integration validates real-world usage - Test fixtures excluded to prevent false failures in CI/CD Implementation Decisions: - Service provider: Auto-discovery, no manual configuration needed - Thread-safe collector: Supports parallel test execution - Fallback hierarchy: Works in various project structures - Performance target: <1ms per test to minimize impact Stories Completed: #2, #3, #4, #5, #6, #7, #10 (7 of 9) Story #8 Skipped: Multi-Release JAR complexity not justified for test reporter Story #9 Remaining: Comprehensive documentation Co-Authored-By: Claude <noreply@anthropic.com>
|
Hi @jsbattig! Thank you for this contribution! Java support is something that a lot of people have asked for! I need some time to review this properly as my time is currently spread thin. I'll review it within the next day or two. Thanks again for taking this on! |
…cken-and-egg problems Addresses GitHub Issue #12 by expanding compiled language rules from "Pure POJOs" to comprehensive "Structural Constructs" covering all zero-logic patterns that must exist before tests can compile. Changes: - Renamed "Pure POJO Definition" to "Structural Constructs Definition" - Added support for 9 construct types: enums, records, data classes, interfaces, exception classes, constants, companion objects, sealed types, annotations - Provided ALLOWED vs BLOCKED examples for each construct type - Added comprehensive test coverage (13 tests, all passing) - Updated decision tree to list all supported structural constructs - Added .code-indexer/ to .gitignore Impact: - Enables proper TDD workflow for Java/Kotlin structural types - Solves chicken-and-egg problem where tests can't compile without types, but TDD Guard blocks creating types without test output - Maintains safety by still blocking constructs with business logic Test Results: - Unit tests: 13/13 passing - Manual E2E validation: Confirmed enum/record/interface creation works - All constructs properly allowed when test file exists 🤖 Generated with [Claude Code](https://claude.ai/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Implement configurable source directory resolution for JUnit5 reporter to support projects with non-standard layouts. Previously hardcoded paths (src/test/java, src/main/java) now dynamically resolved via configuration. Key Changes: - Add SourceDirectoryResolver with system property/env var support - Update TestResultCollector to use dynamic paths with file checking - Convert SourceAnalyzer to instance-based with configurable dirs - Integrate SourceDirectoryResolver throughout pattern detectors - Add comprehensive test coverage (212 tests, all passing) - Update documentation with Gradle/Maven configuration examples Configuration: - System properties: tddguard.testSourceDirs, tddguard.mainSourceDirs - Environment variables: TDDGUARD_TEST_SOURCE_DIRS, etc - Resolution: System properties → Env vars → Defaults - Backward compatible with standard Maven/Gradle layouts Testing: - 13 new SourceDirectoryResolver tests - 18 new integration tests for dynamic path resolution - 4 manual E2E scenarios validated - Zero regressions in existing functionality Bug Fixes: - Fix TestResultCollector file path resolution bug - Now checks file existence in each configured directory - Previously always used first directory incorrectly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
@nizos , no problem, thanks you for spending the time building this amazing tool! |
|
Any rough idea when this going to be merged? @nizos |
|
Was able to validate pretooluse hook worked even today. Hope this PR could make it in! 🙏 |
|
Hi @jsbattig @jordyvanvorselen and @afloresescarcega, I'm sorry for the delay on this review. I have now gone through the full PR in detail. The reporter core is well structured and the effort and thought that went into this is clear and really appreciated. The challenges you identified with compiled languages are also real. That said, I have concerns about scope and architectural fit that I think we need to work through before this can be merged. Compilation fail handlingThe core If the JUnit5 reporter follows the same pattern, detecting javac/Gradle compilation errors and reporting them as failed tests, the core validation layer doesn't need to change. Reporters handle language-specific concerns while the core remains largely language-agnostic. Pattern detection and educational feedbackThe pattern detection goes beyond what any existing reporter does. The current reporters strictly capture test results. Analysis and feedback happen in the validation layer. The closest equivalent we have is linter integration which consumes project-specific rules. This is interesting work and definitely worth exploring further, but it's a separate feature that deserves its own discussion and PR. For the initial reporter, I'd suggest keeping it focused on test result capture. Other items to separate out
Reporter specific notesThe reporter core itself is solid. A few things I noticed:
I realize that this is a lot of feedback on work you've already invested significant effort in, and I'm sorry about that. Can we start with a focused JUnit5 reporter PR? Listener + collector + JSON writer + models + tests, following the Go/Rust pattern for compilation failure handling. No core There are also merge conflicts on the branch, but let's align on the approach first before tackling those. How does that sound? |
|
Hi @jsbattig, thanks for laying the groundwork here. With @nizos's guidance I will be picking up the JUnit5 reporter, taking inspiration from your design while aligning the output with the canonical test.json schema used by other reporters, and splitting the work into smaller PRs per the review feedback. You will be credited for the design reference in commits and PR descriptions. Happy to have you involved if you are still around. |
Sets up the JUnit5 reporter directory following the minitest/rspec reporter conventions: - Gradle Kotlin DSL build with Java 17 toolchain and Maven publishing - Canonical schema model classes (TestResult, TestModule, TestCase, TestError) matching src/contracts/schemas/reporterSchemas.ts - ProjectRootResolver per ADR-009 (accepts absolute and relative paths) and ADR-010 (explicit > TDD_GUARD_PROJECT_ROOT > error; no silent cwd fallback) - README skeleton Tests not yet run locally pending Java 17 environment setup. ProjectRootResolverTest covers 8 cases: missing config, explicit path precedence, env var fallback, absolute and relative path handling, and cwd-within-root validation. Refs nizos#67, nizos#80. Design inspired by @jsbattig's listener architecture.
|
Hiro, thanks.
I saw the reviews, and I honestly didn't have time to get back to this, so
I appreciate it.
Seba
…On Sun, Apr 12, 2026 at 2:12 PM Hiro-Chiba ***@***.***> wrote:
*Hiro-Chiba* left a comment (nizos/tdd-guard#80)
<#80 (comment)>
Hi @jsbattig <https://github.com/jsbattig>, thanks for laying the
groundwork here. With @nizos <https://github.com/nizos>'s guidance I will
be picking up the JUnit5 reporter by using parts of your work as a base and
splitting it into smaller PRs matching the review feedback. You will be
credited in the commits and PR descriptions. Happy to have you involved if
you are still around.
—
Reply to this email directly, view it on GitHub
<#80 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AANVFBOLZY423T3U6BVHEYD4VPTC7AVCNFSM6AAAAACLRDWUB6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DEMZSGU2DIMRXGI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Implements the result capture pipeline for the JUnit5 reporter: - TddGuardListener registers via META-INF/services and writes results on test plan completion. Activates only when TDD_GUARD_PROJECT_ROOT is set so the jar is safe to include on a classpath without opting in. - TestResultCollector groups outcomes by moduleId (fully qualified class name). Pure data layer with no JUnit Platform dependency so it is directly unit-testable. - TestJsonWriter serializes to the canonical schema defined in src/contracts/schemas/reporterSchemas.ts with atomic temp-file write. No external JSON library dependency. Tests: 11 cases for TestJsonWriter (passed/failed/skipped, escaping, atomic write, nested directory creation) and 9 for TestResultCollector (grouping, state extraction, throwable handling, insertion order). Tests not yet run locally pending Java 17 environment setup. Refs nizos#67, nizos#80.
Sets up the JUnit5 reporter directory following the minitest/rspec reporter conventions: - Gradle Kotlin DSL build with Java 17 toolchain and Maven publishing - Canonical schema model classes (TestResult, TestModule, TestCase, TestError) matching src/contracts/schemas/reporterSchemas.ts - ProjectRootResolver per ADR-009 (accepts absolute and relative paths) and ADR-010 (explicit > TDD_GUARD_PROJECT_ROOT > error; no silent cwd fallback) - README skeleton Tests not yet run locally pending Java 17 environment setup. ProjectRootResolverTest covers 8 cases: missing config, explicit path precedence, env var fallback, absolute and relative path handling, and cwd-within-root validation. Refs nizos#67, nizos#80. Design inspired by @jsbattig's listener architecture.
Implements the result capture pipeline for the JUnit5 reporter: - TddGuardListener registers via META-INF/services and writes results on test plan completion. Activates only when TDD_GUARD_PROJECT_ROOT is set so the jar is safe to include on a classpath without opting in. - TestResultCollector groups outcomes by moduleId (fully qualified class name). Pure data layer with no JUnit Platform dependency so it is directly unit-testable. - TestJsonWriter serializes to the canonical schema defined in src/contracts/schemas/reporterSchemas.ts with atomic temp-file write. No external JSON library dependency. Tests: 11 cases for TestJsonWriter (passed/failed/skipped, escaping, atomic write, nested directory creation) and 9 for TestResultCollector (grouping, state extraction, throwable handling, insertion order). Tests not yet run locally pending Java 17 environment setup. Refs nizos#67, nizos#80.
Sets up the JUnit5 reporter directory following the minitest/rspec reporter conventions: - Gradle Kotlin DSL build with Java 17 toolchain and Maven publishing - Canonical schema model classes (TestResult, TestModule, TestCase, TestError) matching src/contracts/schemas/reporterSchemas.ts - ProjectRootResolver per ADR-009 (accepts absolute and relative paths) and ADR-010 (explicit > TDD_GUARD_PROJECT_ROOT > error; no silent cwd fallback) - README skeleton Tests not yet run locally pending Java 17 environment setup. ProjectRootResolverTest covers 8 cases: missing config, explicit path precedence, env var fallback, absolute and relative path handling, and cwd-within-root validation. Refs nizos#67, nizos#80. Design inspired by @jsbattig's listener architecture.
Implements the result capture pipeline for the JUnit5 reporter: - TddGuardListener registers via META-INF/services and writes results on test plan completion. Activates only when TDD_GUARD_PROJECT_ROOT is set so the jar is safe to include on a classpath without opting in. - TestResultCollector groups outcomes by moduleId (fully qualified class name). Pure data layer with no JUnit Platform dependency so it is directly unit-testable. - TestJsonWriter serializes to the canonical schema defined in src/contracts/schemas/reporterSchemas.ts with atomic temp-file write. No external JSON library dependency. Tests: 11 cases for TestJsonWriter (passed/failed/skipped, escaping, atomic write, nested directory creation) and 9 for TestResultCollector (grouping, state extraction, throwable handling, insertion order). Tests not yet run locally pending Java 17 environment setup. Refs nizos#67, nizos#80.
Sets up the JUnit5 reporter directory following the minitest/rspec reporter conventions: - Gradle Kotlin DSL build with Java 17 toolchain and Maven publishing - Canonical schema model classes (TestResult, TestModule, TestCase, TestError) matching src/contracts/schemas/reporterSchemas.ts - ProjectRootResolver per ADR-009 (accepts absolute and relative paths) and ADR-010 (explicit > TDD_GUARD_PROJECT_ROOT > error; no silent cwd fallback) - README skeleton Tests not yet run locally pending Java 17 environment setup. ProjectRootResolverTest covers 8 cases: missing config, explicit path precedence, env var fallback, absolute and relative path handling, and cwd-within-root validation. Refs #67, #80. Design inspired by @jsbattig's listener architecture.
Implements the result capture pipeline for the JUnit5 reporter: - TddGuardListener registers via META-INF/services and writes results on test plan completion. Activates only when TDD_GUARD_PROJECT_ROOT is set so the jar is safe to include on a classpath without opting in. - TestResultCollector groups outcomes by moduleId (fully qualified class name). Pure data layer with no JUnit Platform dependency so it is directly unit-testable. - TestJsonWriter serializes to the canonical schema defined in src/contracts/schemas/reporterSchemas.ts with atomic temp-file write. No external JSON library dependency. Tests: 11 cases for TestJsonWriter (passed/failed/skipped, escaping, atomic write, nested directory creation) and 9 for TestResultCollector (grouping, state extraction, throwable handling, insertion order). Tests not yet run locally pending Java 17 environment setup. Refs #67, #80.
Extends TDD Guard to Java ecosystem to enable AI-driven TDD enforcement for Java/Kotlin projects. Discovered during implementation that strict incremental TDD rules conflict with compiled languages' compilation phase, requiring language-specific adaptations.
WHY This Change:
Core Features:
Java/Kotlin POJO Support (WHY NEEDED):
Problem: Strict incremental TDD blocks compilation phase stubs in Java. Tests won't compile without class/method stubs, but TDD Guard blocked stubs without test.json (which only exists after successful compilation).
Solution: Research-backed rules from Kent Beck's "Obvious Implementation":
Rationale: Java POJOs are structural code (data holders), not behavioral. Community consensus: Testing simple getters/setters is wasteful, they're covered by integration tests. Kent Beck: "If you know what to type and can do it quickly, then do it."
Distribution WHY:
Boy Scout Rule WHY:
Fixed golangci-lint compatibility because tests were failing. Updated for v1.64+ (current version) to ensure CI/CD works properly. This benefits all contributors, not just this PR.
Testing WHY:
Implementation Decisions:
Stories Completed: #2, #3, #4, #5, #6, #7, #10 (7 of 9)
Story #8 Skipped: Multi-Release JAR complexity not justified for test reporter
Story #9 Remaining: Comprehensive documentation