Skip to content

Commit

Permalink
Add recipes for migrating Arquillian from JUnit 4 to JUnit 5. (#654)
Browse files Browse the repository at this point in the history
* [652] Add recipes for migrating Arquillian from JUnit 4 to JUnit 5.

Signed-off-by: James R. Perkins <[email protected]>

* Create a separate recipe yaml and test class

* [652] Ensure the MethodOrder is imported.

Signed-off-by: James R. Perkins <[email protected]>

* Order imports and inline variables & lambda returns

* Add ReplaceArquillianInSequenceAnnotationTest

* Light polish

* Replace `inSequenceAnnotationToOrderAnnotation` with `ChangeType`

* Use JavaTemplate to add the new annotation

* Rename recipe and include with JUnit 4 to 5 recipe

---------

Signed-off-by: James R. Perkins <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
  • Loading branch information
jamezp and timtebeek authored Dec 22, 2024
1 parent fc9d8b4 commit e9009a2
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 2 deletions.
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ dependencies {
exclude(group = "org.yaml", module = "snakeyaml")
}
testRuntimeOnly("org.easymock:easymock:latest.release")
testRuntimeOnly("org.testng:testng:latest.release")
testRuntimeOnly("org.jboss.arquillian.junit:arquillian-junit-core:latest.release")
testRuntimeOnly("org.mockito.kotlin:mockito-kotlin:latest.release")
testRuntimeOnly("org.testcontainers:testcontainers:latest.release")
testRuntimeOnly("org.testcontainers:nginx:latest.release")
testRuntimeOnly("org.testng:testng:latest.release")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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.arquillian;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.*;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.service.AnnotationService;
import org.openrewrite.java.tree.J;

import java.util.Comparator;

public class ReplaceArquillianInSequenceAnnotation extends Recipe {

@Override
public String getDisplayName() {
return "Arquillian JUnit 4 `@InSequence` to JUnit Jupiter `@Order`";
}

@Override
public String getDescription() {
return "Transforms the Arquillian JUnit 4 `@InSequence` to the JUnit Jupiter `@Order`.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return Preconditions.check(
new UsesType<>("org.jboss.arquillian.junit.InSequence", false),
new JavaIsoVisitor<ExecutionContext>() {
private final String IN_SEQUENCE = "org.jboss.arquillian.junit.InSequence";
private final String TEST_METHOD_ORDER = "org.junit.jupiter.api.TestMethodOrder";
private final String METHOD_ORDERER = "org.junit.jupiter.api.MethodOrderer";
private final AnnotationMatcher IN_SEQUENCE_MATCHER = new AnnotationMatcher("@" + IN_SEQUENCE);
private final AnnotationMatcher TEST_METHOD_ORDER_MATCHER = new AnnotationMatcher("@" + TEST_METHOD_ORDER);

@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
doAfterVisit(new ChangeType(IN_SEQUENCE, "org.junit.jupiter.api.Order", true).getVisitor());
return super.visitClassDeclaration(classDecl, ctx);
}

@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx);
if (service(AnnotationService.class).matches(updateCursor(m), IN_SEQUENCE_MATCHER)) {
J.ClassDeclaration classWithInSequenceMethods = getCursor().firstEnclosing(J.ClassDeclaration.class);
if (classWithInSequenceMethods != null) {
doAfterVisit(new JavaIsoVisitor<ExecutionContext>() {
@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);
if (cd.getName().equals(classWithInSequenceMethods.getName()) &&
!service(AnnotationService.class).matches(updateCursor(cd), TEST_METHOD_ORDER_MATCHER)) {
maybeAddImport(METHOD_ORDERER);
maybeAddImport(TEST_METHOD_ORDER);
return JavaTemplate.builder("@TestMethodOrder(MethodOrderer.class)")
.imports(METHOD_ORDERER, TEST_METHOD_ORDER)
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, "junit-jupiter-api-5"))
.build()
.apply(getCursor(), classDecl.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName)));
}
return cd;
}
});
}
}
return m;
}
}
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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.
*/
@NullMarked
package org.openrewrite.java.testing.arquillian;

import org.jspecify.annotations.NullMarked;
41 changes: 41 additions & 0 deletions src/main/resources/META-INF/rewrite/arquillian.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#
# Copyright 2024 the original author or authors.
# <p>
# Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
# <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.
#

---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5
displayName: Use Arquillian JUnit 5 Extension
description: Migrates Arquillian JUnit 4 to JUnit 5.
tags:
- testing
- junit
- arquillian
recipeList:
- org.openrewrite.java.testing.junit5.RunnerToExtension:
runners:
- org.jboss.arquillian.junit.Arquillian
extension: org.jboss.arquillian.junit5.ArquillianExtension
- org.openrewrite.java.dependencies.ChangeDependency:
oldGroupId: org.jboss.arquillian.junit
oldArtifactId: arquillian-junit-container
newGroupId: org.jboss.arquillian.junit5
newArtifactId: arquillian-junit5-container
newVersion: x
- org.openrewrite.java.testing.arquillian.ReplaceArquillianInSequenceAnnotation
- org.openrewrite.java.ChangePackage:
oldPackageName: org.jboss.arquillian.junit
newPackageName: org.jboss.arquillian.junit5
recursive: true
2 changes: 1 addition & 1 deletion src/main/resources/META-INF/rewrite/junit5.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: org.jbehave.core.junit.JUnitStories
newFullyQualifiedTypeName: org.jbehave.core.junit.JupiterStories
- org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5
- org.openrewrite.java.testing.dbrider.MigrateDbRiderSpringToDbRiderJUnit5

---
Expand Down Expand Up @@ -322,4 +323,3 @@ recipeList:
groupId: org.junit.platform
artifactId: junit-platform-surefire-provider
version: 1.1.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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.arquillian;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.mavenProject;
import static org.openrewrite.maven.Assertions.pomXml;

class ArquillianJUnit4ToArquillianJunit5Test implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec.recipeFromResource(
"/META-INF/rewrite/arquillian.yml",
"org.openrewrite.java.testing.arquillian.ArquillianJUnit4ToArquillianJUnit5");
}

@DocumentExample
@Test
void convert() {
rewriteRun(
mavenProject("project",
//language=xml
pomXml(
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.openrewrite</groupId>
<artifactId>arquillian</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<version>1.7.0.Final</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
""",
"""
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.openrewrite</groupId>
<artifactId>arquillian</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.jboss.arquillian.junit5</groupId>
<artifactId>arquillian-junit5-container</artifactId>
<version>1.9.1.Final</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
"""
)
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2024 the original author or authors.
* <p>
* Licensed under the Moderne Source Available License (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://docs.moderne.io/licensing/moderne-source-available-license
* <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.arquillian;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.java;

class ReplaceArquillianInSequenceAnnotationTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec
.parser(JavaParser.fromJavaVersion().classpath("arquillian-junit-core"))
.recipe(new ReplaceArquillianInSequenceAnnotation());
}

@DocumentExample
@Test
void replaceInSequenceAnnotation() {
rewriteRun(
//language=java
java(
"""
import org.jboss.arquillian.junit.InSequence;
class A {
@InSequence(2)
void second() {}
@InSequence(1)
void first() {}
}
""",
"""
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(MethodOrderer.class)
class A {
@Order(2)
void second() {}
@Order(1)
void first() {}
}
"""
)
);
}
}

0 comments on commit e9009a2

Please sign in to comment.