Backend · Compilers
JUnit 4 → 5 Translator
A source-to-source translator that automatically migrates JUnit 4 test suites to JUnit 5 using compiler techniques — an ANTLR grammar for Java that parses and rewrites tests.
The problem
At Encora, a large legacy monolith carried a test suite written entirely in JUnit 4. Migrating
it to JUnit 5 by hand would have meant hundreds of hours of tedious, error-prone refactoring —
and many of the changes aren't simple find-and-replace. Renaming @Before to
@BeforeEach is easy; faithfully rewriting @Test(expected = ...) into
assertThrows, or rules into extensions, is a structural transformation that text
substitution gets wrong.
The approach: a real compiler front-end
I built an open-source source-to-source translator that treats the migration as a compiler problem. It uses an ANTLR grammar for Java to parse each test file into a parse tree, walks that tree to recognize JUnit 4 constructs, and rewrites them into their JUnit 5 equivalents while preserving the surrounding code and formatting.
Before / after
The transform handles the structural cases, not just the cosmetic ones:
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class OrderTest {
@Before
public void setUp() { ... }
@Test(expected = IllegalStateException.class)
public void rejectsEmptyCart() {
new Order().checkout();
}
} import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class OrderTest {
@BeforeEach
void setUp() { ... }
@Test
void rejectsEmptyCart() {
assertThrows(IllegalStateException.class,
() -> new Order().checkout());
}
} Why it matters
- Parsing the real grammar makes the rewrites reliable where regex-based scripts break — expected exceptions, parameterized tests, rules, and static imports all transform correctly.
- It runs across an entire codebase at once, turning a multi-week manual effort into a repeatable command.
- It's the practical side of CS fundamentals I enjoy: grammars, parse trees, and AST rewriting applied to a concrete engineering cost.
Outcome
The translator eliminated hundreds of hours of manual refactoring on the migration, and is available as open source on GitHub.