Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recipes for migrating Arquillian from JUnit 4 to JUnit 5. #654

Merged
merged 10 commits into from
Dec 22, 2024
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,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,121 @@
/*
* 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.ChangeType;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.search.FindAnnotations;
import org.openrewrite.java.search.UsesType;
import org.openrewrite.java.tree.*;
import org.openrewrite.marker.Markers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static java.util.Collections.emptyList;
import static org.openrewrite.Tree.randomId;

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 InSequenceToOrderVisitor());
}

public static class InSequenceToOrderVisitor extends JavaIsoVisitor<ExecutionContext> {
private static final JavaType.Class testMethodOrderType = JavaType.ShallowClass.build("org.junit.jupiter.api.TestMethodOrder");
private static final JavaType.Class methodOrderType = JavaType.ShallowClass.build("org.junit.jupiter.api.MethodOrderer");
private static final JavaType.Class orderType = JavaType.ShallowClass.build("org.junit.jupiter.api.Order");

@Override
public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) {
J.ClassDeclaration cd = super.visitClassDeclaration(classDecl, ctx);

timtebeek marked this conversation as resolved.
Show resolved Hide resolved


return cd;
}

@Override
public J.MethodDeclaration visitMethodDeclaration(J.MethodDeclaration method, ExecutionContext ctx) {
J.MethodDeclaration m = super.visitMethodDeclaration(method, ctx);
Set<J.Annotation> inSequenceAnnotations = FindAnnotations.find(m, "@org.jboss.arquillian.junit.InSequence");
if (!inSequenceAnnotations.isEmpty()) {
doAfterVisit(new ChangeType(
"org.jboss.arquillian.junit.InSequence",
"org.junit.jupiter.api.Order",
true).getVisitor());

J.ClassDeclaration classDeclaration = getCursor().dropParentUntil(org.openrewrite.java.tree.J.ClassDeclaration.class::isInstance)
.getValue();
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(classDeclaration.getName())) {
if (FindAnnotations.find(cd, "@" + testMethodOrderType.getFullyQualifiedName()).isEmpty()) {
List<J.Annotation> annotations = new ArrayList<>(cd.getLeadingAnnotations());
annotations.add(new J.Annotation(randomId(), Space.EMPTY, Markers.EMPTY,
new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), testMethodOrderType.getClassName(), testMethodOrderType, null),
JContainer.build(Space.EMPTY,
Collections.singletonList(
new JRightPadded<>(
new J.Literal(
randomId(),
Space.EMPTY,
Markers.EMPTY,
methodOrderType,
methodOrderType.getClassName() + ".class",
null,
JavaType.Primitive.None),
Space.EMPTY,
Markers.EMPTY
)
),
Markers.EMPTY
)
));
cd = cd.withLeadingAnnotations(annotations);
maybeAddImport(testMethodOrderType);
maybeAddImport(methodOrderType.getFullyQualifiedName(), null, false);
}
}
cd = maybeAutoFormat(classDecl, cd, cd.getName(), ctx, getCursor().getParentTreeCursor());
return cd;
}
});
}
return maybeAutoFormat(method, m, m.getName(), ctx, getCursor().getParentTreeCursor());
}
}
}
62 changes: 62 additions & 0 deletions src/main/resources/META-INF/rewrite/arquillian.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#
# 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.junit5.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
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.testing.junit5.ArquillianJUnit4ToArquillianJunit5BestPractices
displayName: Use Arquillian JUnit 5 Extension with best practices
description: Migrates Arquillian `@RunWith` `Arquillian` to the JUnit Jupiter `@ExtendWith` `ArquillianExtension` with best practices.
tags:
- testing
- junit
- arquillian
recipeList:
- org.openrewrite.java.testing.junit5.JUnit4to5Migration
- org.openrewrite.java.testing.junit5.ArquillianJUnit4ToArquillianJunit5
- org.openrewrite.java.testing.junit5.StaticImports
- org.openrewrite.java.testing.junit5.CleanupAssertions
- org.openrewrite.java.testing.cleanup.AssertLiteralBooleanToFailRecipe
- org.openrewrite.java.testing.cleanup.RemoveTestPrefix
- org.openrewrite.java.testing.junit5.AddParameterizedTestAnnotation
- org.openrewrite.java.testing.junit5.RemoveDuplicateTestTemplates
- org.openrewrite.java.testing.junit5.RemoveTryCatchFailBlocks
- org.openrewrite.java.testing.junit5.LifecycleNonPrivate
- org.openrewrite.java.testing.junit5.AssertThrowsOnLastStatement
1 change: 0 additions & 1 deletion src/main/resources/META-INF/rewrite/junit5.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,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,76 @@
/*
* 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.junit5.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() {}
}
"""
)
);
}
}
Loading