Skip to content

Commit

Permalink
Add JMockit's MockUp to Mockito migration (#599)
Browse files Browse the repository at this point in the history
* Add JMockit's MockUp to Mockito migration

* Adopt mockito-core:5.+ through parserClasspath

* Apply bot code suggestions

* Add type check for new class statement

* Fix statement construction

* Remove debug statement

* Fix code format

* Use CallRealMethod for non mock methods

* Update src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/test/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockitoTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update src/main/java/org/openrewrite/java/testing/jmockit/JMockitMockUpToMockito.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Add description about private methods

* Update JMockitMockUpToMockitoTest.java

* Fix UT to match gralde build order

* Add setUp/tearDown support

* Add MockUp params support

* Remove useless

* Fix JavaTemplate type inference

* Remove unused local variables

* MockUp to try-with-resource

* Add import class test

* Add multiple mockUp test

* Apply bot suggestions

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Remove useless type  cast

* Fix variable naming

* Remove fqn from naming

* Remove unneeded method call

* Shorter var naming

* Update JMockitMockUpToMockitoTest.java

* Refactor mockup migration to resuse existing code and cleanup

* Resolve deprecated print()

* Utilize LambdaBlockToExpression

* Make constants

* Apply bot suggestions

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Apply formatter and fix compilation

* Place binary operators on the same line

* Add missing language hints

* Adopt AtomicReference instead of array element zero

* Fix workflow build

* Update src/main/java/org/openrewrite/java/testing/mockito/MockitoUtils.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Use mockito-core-3 instead of mockito-core-5

* Inline constants used once; Explicitly name reference var

* Use now public VariableReferences.findRhsReferences

---------

Co-authored-by: Tim te Beek <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tim te Beek <[email protected]>
Co-authored-by: Shivani Sharma <[email protected]>
  • Loading branch information
5 people authored Nov 2, 2024
1 parent 56fffc0 commit 72232f7
Show file tree
Hide file tree
Showing 7 changed files with 1,410 additions and 183 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2024 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.mockito;

import org.jspecify.annotations.Nullable;
import org.openrewrite.Cursor;
import org.openrewrite.ExecutionContext;
import org.openrewrite.java.AnnotationMatcher;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Statement;

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

public class MockitoUtils {
public static J.ClassDeclaration maybeAddMethodWithAnnotation(
JavaVisitor visitor,
J.ClassDeclaration classDecl,
ExecutionContext ctx,
boolean isPublic,
String methodName,
String methodAnnotationSignature,
String methodAnnotationToAdd,
String additionalClasspathResource,
String importToAdd,
String methodAnnotationParameters
) {
if (hasMethodWithAnnotation(classDecl, new AnnotationMatcher(methodAnnotationSignature))) {
return classDecl;
}

J.MethodDeclaration firstTestMethod = getFirstTestMethod(
classDecl.getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance)
.map(J.MethodDeclaration.class::cast).collect(Collectors.toList()));

visitor.maybeAddImport(importToAdd);
String tplStr = methodAnnotationToAdd + methodAnnotationParameters +
(isPublic ? " public" : "") + " void " + methodName + "() {}";
return JavaTemplate.builder(tplStr)
.contextSensitive()
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, additionalClasspathResource))
.imports(importToAdd)
.build()
.apply(
new Cursor(visitor.getCursor().getParentOrThrow(), classDecl),
(firstTestMethod != null) ?
firstTestMethod.getCoordinates().before() :
classDecl.getBody().getCoordinates().lastStatement()
);
}

private static boolean hasMethodWithAnnotation(J.ClassDeclaration classDecl, AnnotationMatcher annotationMatcher) {
for (Statement statement : classDecl.getBody().getStatements()) {
if (statement instanceof J.MethodDeclaration) {
J.MethodDeclaration methodDeclaration = (J.MethodDeclaration) statement;
List<J.Annotation> allAnnotations = methodDeclaration.getAllAnnotations();
for (J.Annotation annotation : allAnnotations) {
if (annotationMatcher.matches(annotation)) {
return true;
}
}
}
}
return false;
}

private static J.@Nullable MethodDeclaration getFirstTestMethod(List<J.MethodDeclaration> methods) {
for (J.MethodDeclaration methodDeclaration : methods) {
for (J.Annotation annotation : methodDeclaration.getLeadingAnnotations()) {
if ("Test".equals(annotation.getSimpleName())) {
return methodDeclaration;
}
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.util.*;
import java.util.stream.Collectors;

import static org.openrewrite.java.testing.mockito.MockitoUtils.maybeAddMethodWithAnnotation;

public class PowerMockitoMockStaticToMockito extends Recipe {

@Override
Expand Down Expand Up @@ -213,32 +215,6 @@ private static boolean isFieldAlreadyDefined(J.Block classBody, String fieldName
return false;
}

private static J.@Nullable MethodDeclaration getFirstTestMethod(List<J.MethodDeclaration> methods) {
for (J.MethodDeclaration methodDeclaration : methods) {
for (J.Annotation annotation : methodDeclaration.getLeadingAnnotations()) {
if ("Test".equals(annotation.getSimpleName())) {
return methodDeclaration;
}
}
}
return null;
}

private static boolean hasMethodWithAnnotation(J.ClassDeclaration classDecl, AnnotationMatcher annotationMatcher) {
for (Statement statement : classDecl.getBody().getStatements()) {
if (statement instanceof J.MethodDeclaration) {
J.MethodDeclaration methodDeclaration = (J.MethodDeclaration) statement;
List<J.Annotation> allAnnotations = methodDeclaration.getAllAnnotations();
for (J.Annotation annotation : allAnnotations) {
if (annotationMatcher.matches(annotation)) {
return true;
}
}
}
}
return false;
}

private static boolean isStaticMockAlreadyClosed(J.Identifier staticMock, J.Block methodBody) {
for (Statement statement : methodBody.getStatements()) {
if (statement instanceof J.MethodInvocation) {
Expand Down Expand Up @@ -465,7 +441,7 @@ private J.ClassDeclaration addFieldDeclarationForMockedTypes(J.ClassDeclaration

private J.ClassDeclaration maybeAddSetUpMethodBody(J.ClassDeclaration classDecl, ExecutionContext ctx) {
String testGroupsAsString = getTestGroupsAsString();
return maybeAddMethodWithAnnotation(classDecl, ctx, "setUpStaticMocks",
return maybeAddMethodWithAnnotation(this, classDecl, ctx, false, "setUpStaticMocks",
setUpMethodAnnotationSignature, setUpMethodAnnotation,
additionalClasspathResource, setUpImportToAdd, testGroupsAsString);
}
Expand All @@ -483,38 +459,12 @@ private String getTestGroupsAsString() {

private J.ClassDeclaration maybeAddTearDownMethodBody(J.ClassDeclaration classDecl, ExecutionContext ctx) {
String testGroupsAsString = (getTestGroupsAsString().isEmpty()) ? tearDownMethodAnnotationParameters : getTestGroupsAsString();
return maybeAddMethodWithAnnotation(classDecl, ctx, "tearDownStaticMocks",
return maybeAddMethodWithAnnotation(this, classDecl, ctx, false, "tearDownStaticMocks",
tearDownMethodAnnotationSignature,
tearDownMethodAnnotation,
additionalClasspathResource, tearDownImportToAdd, testGroupsAsString);
}

private J.ClassDeclaration maybeAddMethodWithAnnotation(J.ClassDeclaration classDecl, ExecutionContext ctx,
String methodName, String methodAnnotationSignature,
String methodAnnotationToAdd,
String additionalClasspathResource, String importToAdd,
String methodAnnotationParameters) {
if (hasMethodWithAnnotation(classDecl, new AnnotationMatcher(methodAnnotationSignature))) {
return classDecl;
}

J.MethodDeclaration firstTestMethod = getFirstTestMethod(
classDecl.getBody().getStatements().stream().filter(J.MethodDeclaration.class::isInstance)
.map(J.MethodDeclaration.class::cast).collect(Collectors.toList()));

maybeAddImport(importToAdd);
return JavaTemplate.builder(methodAnnotationToAdd + methodAnnotationParameters + " void " + methodName + "() {}")
.contextSensitive()
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, additionalClasspathResource))
.imports(importToAdd)
.build()
.apply(
new Cursor(getCursor().getParentOrThrow(), classDecl),
(firstTestMethod != null) ?
firstTestMethod.getCoordinates().before() :
classDecl.getBody().getCoordinates().lastStatement()
);
}

private J.MethodInvocation modifyWhenMethodInvocation(J.MethodInvocation whenMethod) {
List<Expression> methodArguments = whenMethod.getArguments();
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/META-INF/rewrite/jmockit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ tags:
- jmockit
recipeList:
- org.openrewrite.java.testing.jmockit.JMockitBlockToMockito
- org.openrewrite.java.testing.jmockit.JMockitMockUpToMockito
- org.openrewrite.java.testing.jmockit.JMockitAnnotatedArgumentToMockito
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: mockit.Mocked
Expand Down
Loading

0 comments on commit 72232f7

Please sign in to comment.