Skip to content

Commit

Permalink
Fix #5 Handle @RunWith(SpringRunner.class) in junit 4 -> 5 migration
Browse files Browse the repository at this point in the history
This depends on currently unpublished changes in rewrite core libraries
  • Loading branch information
sambsnyd committed Nov 2, 2020
1 parent e56ff66 commit beb6b19
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:latest.release")
testImplementation("org.junit.jupiter:junit-jupiter-params:latest.release")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:latest.release")
testRuntimeOnly("org.springframework:spring-test:latest.release")
"afterImplementation"("org.junit.jupiter:junit-jupiter-api:latest.release")
"afterImplementation"("org.junit.jupiter:junit-jupiter-params:latest.release")
"afterRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:latest.release")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright 2020 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.testing.junit5;

import org.openrewrite.Formatting;
import org.openrewrite.java.JavaIsoRefactorVisitor;
import org.openrewrite.java.search.SemanticallyEqual;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static org.openrewrite.Formatting.EMPTY;
import static org.openrewrite.Tree.randomId;

/**
* JUnit4 Spring test classes are annotated with @RunWith(SpringRunner.class)
* Turn this into the JUnit5-compatible @ExtendsWith(SpringExtension.class)
*/
public class SpringRunnerToSpringExtension extends JavaIsoRefactorVisitor {
private static final JavaType.Class runWithType = JavaType.Class.build("org.junit.runner.RunWith");
private static final J.Ident runWithIdent = J.Ident.build(
randomId(),
"RunWith",
runWithType,
EMPTY);
private static final JavaType.Class springRunnerType = JavaType.Class.build("org.springframework.test.context.junit4.SpringRunner");
private static final JavaType.Class extendWithType = JavaType.Class.build("org.junit.jupiter.api.extension.ExtendWith");
private static final J.Ident extendWithIdent = J.Ident.build(
randomId(),
"ExtendWith",
extendWithType,
EMPTY
);
private static final JavaType.Class springExtensionType = JavaType.Class.build("org.springframework.test.context.junit.jupiter.SpringExtension");


// Reference @RunWith(SpringRunner.class) annotation for semantically equal to compare against
private static final J.Annotation runWithSpringRunnerAnnotation = new J.Annotation(
randomId(),
runWithIdent,
new J.Annotation.Arguments(
randomId(),
Collections.singletonList(
new J.FieldAccess(
randomId(),
J.Ident.build(
randomId(),
"SpringRunner",
springRunnerType,
EMPTY
),
J.Ident.build(randomId(), "class", null, EMPTY),
JavaType.Class.build("java.lang.Class"),
EMPTY
)
),
EMPTY
),
EMPTY
);

private static final J.Annotation extendWithSpringExtensionAnnotation = new J.Annotation(
randomId(),
extendWithIdent,
new J.Annotation.Arguments(
randomId(),
Collections.singletonList(
new J.FieldAccess(
randomId(),
J.Ident.build(
randomId(),
"SpringExtension",
springExtensionType,
EMPTY
),
J.Ident.build(randomId(), "class", null, EMPTY),
JavaType.Class.build("java.lang.Class"),
EMPTY
)
),
EMPTY
),
EMPTY
);

public SpringRunnerToSpringExtension() {
setCursoringOn();
}

@Override
public J.ClassDecl visitClassDecl(J.ClassDecl cd) {
List<J.Annotation> annotations = cd.getAnnotations().stream()
.map(this::springRunnerToSpringExtension)
.collect(Collectors.toList());

return cd.withAnnotations(annotations);
}

/**
* Converts annotations like @RunWith(SpringRunner.class) into @ExtendWith(SpringExtension.class)
* Leaves other annotations untouched and returns as-is.
*
* NOT a pure function. Side effects include:
* Adding imports for ExtendWith and SpringExtension
* Removing imports for RunWith and SpringRunner
*/
private J.Annotation springRunnerToSpringExtension(J.Annotation maybeSpringRunner) {
if(!new SemanticallyEqual(runWithSpringRunnerAnnotation).visit(maybeSpringRunner)) {
return maybeSpringRunner;
}
Formatting originalFormatting = maybeSpringRunner.getFormatting();
J.ClassDecl parent = getCursor().firstEnclosing(J.ClassDecl.class);
assert parent != null;
J.Annotation extendWithSpringExtension = extendWithSpringExtensionAnnotation.withFormatting(originalFormatting);
maybeAddImport(extendWithType);
maybeAddImport(springExtensionType);
maybeRemoveImport(springRunnerType);
maybeRemoveImport(runWithType);

return extendWithSpringExtension;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2020 the original author or authors.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openrewrite.java.testing.junit5

import org.junit.Test
import org.openrewrite.RefactorVisitorTestForParser
import org.openrewrite.java.JavaParser
import org.openrewrite.java.tree.J

class SpringRunnerToSpringExtensionTest : RefactorVisitorTestForParser<J.CompilationUnit> {
override val parser: JavaParser = JavaParser.fromJavaVersion()
.classpath("junit", "spring-test")
.build()

override val visitors = listOf(SpringRunnerToSpringExtension())

@Test
fun basicRunnerToExtension() = assertRefactored(
before = """
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
class A {}
""",
after = """
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
class A {}
"""
)

@Test
fun leavesOtherRunnersAlone() = assertUnchanged(
before = """
package a;
import org.junit.runner.RunWith;
@RunWith(B.class)
class A {}
""",
dependencies = listOf(
"""
package a;
class B {}
"""
)
)
}

0 comments on commit beb6b19

Please sign in to comment.