Skip to content

Commit 8e1dffb

Browse files
JMockit to Mockito Migration Recipe - Rewrite Expectations Block (#415)
* Recipe to convert JMockit Expectations block to Mockito.when statement --------- Co-authored-by: Kun Li <[email protected]>
1 parent 6e58483 commit 8e1dffb

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ recipeDependencies {
1919
parserClasspath("com.github.tomakehurst:wiremock-jre8:2.35.0")
2020
parserClasspath("org.mockito:mockito-all:1.10.19")
2121
parserClasspath("org.mockito:mockito-core:3.+")
22+
parserClasspath("org.jmockit:jmockit:1.49")
2223
parserClasspath("org.mockito:mockito-junit-jupiter:3.+")
2324
parserClasspath("org.powermock:powermock-api-mockito:1.7.+")
2425
parserClasspath("org.powermock:powermock-core:1.7.+")
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.testing.jmockit;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.Preconditions;
22+
import org.openrewrite.Recipe;
23+
import org.openrewrite.TreeVisitor;
24+
import org.openrewrite.java.JavaParser;
25+
import org.openrewrite.java.JavaTemplate;
26+
import org.openrewrite.java.JavaVisitor;
27+
import org.openrewrite.java.search.UsesType;
28+
import org.openrewrite.java.tree.Expression;
29+
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.Statement;
31+
32+
@Value
33+
@EqualsAndHashCode(callSuper = false)
34+
public class JMockitExpectationsToMockitoWhen extends Recipe {
35+
@Override
36+
public String getDisplayName() {
37+
return "Rewrite JMockit Expectations";
38+
}
39+
40+
@Override
41+
public String getDescription() {
42+
return "Rewrites JMockit `Expectations` to `Mockito.when`.";
43+
}
44+
45+
@Override
46+
public TreeVisitor<?, ExecutionContext> getVisitor() {
47+
return Preconditions.check(new UsesType<>("mockit.*", false),
48+
new RewriteExpectationsVisitor());
49+
}
50+
51+
private static class RewriteExpectationsVisitor extends JavaVisitor<ExecutionContext> {
52+
@Override
53+
public J visitNewClass(J.NewClass newClass, ExecutionContext executionContext) {
54+
J.NewClass nc = (J.NewClass) super.visitNewClass(newClass, executionContext);
55+
if (!(nc.getClazz() instanceof J.Identifier)) {
56+
return nc;
57+
}
58+
J.Identifier clazz = (J.Identifier) nc.getClazz();
59+
if (!clazz.getSimpleName().equals("Expectations")) {
60+
return nc;
61+
}
62+
63+
// empty Expectations block is considered invalid
64+
assert nc.getBody() != null : "Expectations block is empty";
65+
66+
// prepare the statements for moving
67+
J.Block innerBlock = (J.Block) nc.getBody().getStatements().get(0);
68+
69+
// TODO: handle multiple mock statements
70+
Statement mockInvocation = innerBlock.getStatements().get(0);
71+
Expression result = ((J.Assignment) innerBlock.getStatements().get(1)).getAssignment();
72+
73+
// apply the template and replace the `new Expectations()` statement coordinates
74+
// TODO: handle exception results with another template
75+
J.MethodInvocation newMethod = JavaTemplate.builder("when(#{any()}).thenReturn(#{});")
76+
.javaParser(JavaParser.fromJavaVersion().classpathFromResources(executionContext, "mockito-core-3.12"))
77+
.staticImports("org.mockito.Mockito.when")
78+
.build()
79+
.apply(
80+
getCursor(),
81+
nc.getCoordinates().replace(),
82+
mockInvocation,
83+
result
84+
);
85+
86+
// handle import changes
87+
maybeAddImport("org.mockito.Mockito", "when");
88+
maybeRemoveImport("mockit.Expectations");
89+
90+
return newMethod.withPrefix(nc.getPrefix());
91+
}
92+
}
93+
}
681 KB
Binary file not shown.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# Copyright 2023 the original author or authors.
3+
# <p>
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
# <p>
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
# <p>
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
---
17+
type: specs.openrewrite.org/v1beta/recipe
18+
name: org.openrewrite.java.testing.jmockit.JMockitToMockito
19+
displayName: Migrate from JMockit to Mockito
20+
description: This recipe will apply changes commonly needed when migrating from JMockit to Mockito.
21+
tags:
22+
- testing
23+
- jmockit
24+
recipeList:
25+
- org.openrewrite.java.ChangeType:
26+
oldFullyQualifiedTypeName: mockit.Mocked
27+
newFullyQualifiedTypeName: org.mockito.Mock
28+
- org.openrewrite.java.ChangeType:
29+
oldFullyQualifiedTypeName: mockit.integration.junit5.JMockitExtension
30+
newFullyQualifiedTypeName: org.mockito.junit.jupiter.MockitoExtension
31+
- org.openrewrite.java.testing.jmockit.JMockitExpectationsToMockitoWhen
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.testing.jmockit;
17+
18+
import static org.openrewrite.java.Assertions.java;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.openrewrite.InMemoryExecutionContext;
22+
import org.openrewrite.java.JavaParser;
23+
import org.openrewrite.test.RecipeSpec;
24+
import org.openrewrite.test.RewriteTest;
25+
26+
class JMockitToMockitoTest implements RewriteTest {
27+
28+
@Override
29+
public void defaults(RecipeSpec spec) {
30+
spec
31+
.parser(JavaParser.fromJavaVersion()
32+
.logCompilationWarningsAndErrors(true)
33+
.classpathFromResources(new InMemoryExecutionContext(),
34+
"junit-jupiter-api-5.9",
35+
"jmockit-1.49",
36+
"mockito-core-3.12",
37+
"mockito-junit-jupiter-3.12"
38+
))
39+
.recipeFromResource(
40+
"/META-INF/rewrite/jmockit.yml",
41+
"org.openrewrite.java.testing.jmockit.JMockitToMockito"
42+
);
43+
}
44+
45+
@Test
46+
void jMockitExpectationsToMockitoWhen() {
47+
//language=java
48+
rewriteRun(
49+
java(
50+
"""
51+
class MyObject {
52+
public String getSomeField() {
53+
return "X";
54+
}
55+
}
56+
"""
57+
),
58+
java(
59+
"""
60+
import static org.junit.jupiter.api.Assertions.assertNull;
61+
62+
import mockit.Expectations;
63+
import mockit.Mocked;
64+
import mockit.integration.junit5.JMockitExtension;
65+
import org.junit.jupiter.api.extension.ExtendWith;
66+
67+
@ExtendWith(JMockitExtension.class)
68+
class MyTest {
69+
@Mocked
70+
MyObject myObject;
71+
72+
void test() {
73+
new Expectations() {{
74+
myObject.getSomeField();
75+
result = null;
76+
}};
77+
assertNull(myObject.getSomeField());
78+
}
79+
}
80+
""",
81+
"""
82+
import static org.junit.jupiter.api.Assertions.assertNull;
83+
import static org.mockito.Mockito.when;
84+
85+
import org.junit.jupiter.api.extension.ExtendWith;
86+
import org.mockito.Mock;
87+
import org.mockito.junit.jupiter.MockitoExtension;
88+
89+
@ExtendWith(MockitoExtension.class)
90+
class MyTest {
91+
@Mock
92+
MyObject myObject;
93+
94+
void test() {
95+
when(myObject.getSomeField()).thenReturn(null);
96+
assertNull(myObject.getSomeField());
97+
}
98+
}
99+
"""
100+
)
101+
);
102+
}
103+
}

0 commit comments

Comments
 (0)