Uber Automates Massive JUnit 5 Migration, Refactors 1.25 Million Lines of Code in Four Months
April 8, 2026
OpenRewrite served as the core refactoring engine, using a custom Bazel aspect to generate LSTs, apply migration recipes, and produce patch data and diagnostics, with Uber building an end-to-end migration recipe that wove OpenRewrite together with custom rules.
Over four months, the migration automated the conversion of more than 75,000 test classes and changed roughly 1.25 million lines of code via a centralized, repeatable process.
Uber scaled the switch from JUnit 4 to JUnit 5 across its Java monorepo, addressing the absence of ongoing JUnit 4 support and limited native Bazel compatibility with JUnit 5.
Lessons highlighted the need for a solid JUnit Platform foundation, broad tooling coverage with OpenRewrite, and the limited practicality of AI-assisted migration for this scale, favoring deterministic methods.
The strategy used preconditions to screen eligible files, avoided partial migrations that could destabilize builds, and targeted high-impact test utilities and conventions through data-driven metrics.
An incremental rollout began with thousands of targets, analyzed failures, added more OpenRewrite recipes, and progressed iteratively to achieve wide coverage.
The full workflow encompassed applying transformations, updating dependencies, validating changes with tests, and orchestrating large-scale rollout with Shepherd, the internal tool that generates diffs and coordinates CI validation.
Key outcomes included enabling Bazel support for JUnit 5, unifying execution of both JUnit 4 and JUnit 5 tests on a single platform, and laying groundwork for future modernization like deeper Bazel integration and API migrations (e.g., Guava to standard Java, Joda-Time to java.time).
A unified JUnit Platform was established to run both JUnit 4 (via Vintage) and JUnit 5 (via Jupiter) tests, facilitated by a custom Bazel-compatible test runner.
Summary based on 1 source
