Motivation
Recently I want to migrate from JUnit assertEquals
to Hamcrest assertThat
and is
to improve readability of my unit tests.
Instead of using regular expression, it seems it is safer to parse the syntax and manipulate it, so I choose JavaParser.
Objective
Here is how existing test looks like.
package com.franzwong.playground;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MyTest {
@Test
public void test() {
String a = "123";
assertEquals("123", a);
}
}
I would like to change it to something like this.
package com.franzwong.playground;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.CoreMatchers.is;
class MyTest {
@Test
public void test() {
String a = "123";
assertThat(a, is("123"));
}
}
Action items:
- Remove the static import of
assertEquals
- Add static import for
assertThat
andis
- Convert
assertEquals("123", a)
toassertThat(a, is("123"))
- Save modified source
Solution
Add Maven dependency for JavaParser
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.16.2</version>
</dependency>
Setup CompilationUnit
Suppose MyTest.java
file is stored in /tmp
folder.
SourceRoot sourceRoot = new SourceRoot(Path.of("/tmp"));
CompilationUnit cu = sourceRoot.parse("", "MyTest.java");
Remove the static import of assertEquals
We just need to walk through the syntax tree. If the import declaration node is found and it is the assertEquals
node, we just remove it.
cu.walk(ImportDeclaration.class, e -> {
if (e.isStatic() && "org.junit.jupiter.api.Assertions.assertEquals".equals(e.getNameAsString())) {
e.remove();
}
});
Add static import for assertThat
and is
Parameters of ImportDeclaration constructor
- 1st parameter is the static method name
- 2nd parameter is true if it is a static import
- 3rd parameter is true if it is asterisk
cu.addImport(new ImportDeclaration("org.hamcrest.MatcherAssert.assertThat", true, false));
cu.addImport(new ImportDeclaration("org.hamcrest.CoreMatchers.is", true, false));
Convert assertEquals("123", a)
to assertThat(a, is("123"))
We walk through the syntax tree again. If it is a MethodCallExpr
node and its name is assertEquals
, we rename it and change its parameters.
cu.walk(MethodCallExpr.class, e -> {
if (!"assertEquals".equals(e.getNameAsString())) {
return;
}
// Rename method
e.setName("assertThat");
// Get the parameter list of `assertEquals`
NodeList<Expression> equalsArgments = e.getArguments();
// Create a new `is` method and assign 1st parameter of `assertEquals` to it
MethodCallExpr isMethod = new MethodCallExpr("is", equalsArgments.get(0));
// Change the parameters
equalsArgments.set(0, equalsArgments.get(1));
equalsArgments.set(1, isMethod);
});
Save modified source
We just need to provide a folder path to it.
sourceRoot.saveAll(Path.of("/tmp/output"));
So that's it. Here is how the whole source code looks like. I hope this tutorial is useful to you.
public static void main(String[] args) {
SourceRoot sourceRoot = new SourceRoot(Path.of("/tmp"));
CompilationUnit cu = sourceRoot.parse("", "MyTest.java");
cu.walk(ImportDeclaration.class, e -> {
if (e.isStatic() && "org.junit.jupiter.api.Assertions.assertEquals".equals(e.getNameAsString())) {
e.remove();
}
});
cu.addImport(new ImportDeclaration("org.hamcrest.MatcherAssert.assertThat", true, false));
cu.addImport(new ImportDeclaration("org.hamcrest.CoreMatchers.is", true, false));
cu.walk(MethodCallExpr.class, e -> {
if (!"assertEquals".equals(e.getNameAsString())) {
return;
}
// Rename method
e.setName("assertThat");
// Get the parameter list of `assertEquals`
NodeList<Expression> equalsArgments = e.getArguments();
// Create a new `is` method and assign 1st parameter of `assertEquals` to it
MethodCallExpr isMethod = new MethodCallExpr("is", equalsArgments.get(0));
// Change the parameters
equalsArgments.set(0, equalsArgments.get(1));
equalsArgments.set(1, isMethod);
});
sourceRoot.saveAll(Path.of("/tmp/output"));
}
Top comments (0)