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

Replace Mockito 1.x any(Class) and anyString() with nullable(Class) #320

Merged
merged 12 commits into from
Mar 7, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright 2021 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.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.*;
import org.openrewrite.java.search.UsesMethod;
import org.openrewrite.java.tree.J;

import java.time.Duration;

/**
* Replace Mockito 1.x `anyString()` with `nullable(String.class)`
*/
public class AnyStringToNullable extends Recipe {
private static final MethodMatcher ANY_STRING = new MethodMatcher("org.mockito.ArgumentMatchers anyString()");
private static final String MOCKITO_CLASS_PATH = "mockito-core-3.12.4";
kunli2 marked this conversation as resolved.
Show resolved Hide resolved

@Override
public String getDisplayName() {
return "Replace Mockito 1.x `anyString()` with `nullable(String.class)`";
}

@Override
public String getDescription() {
return "Since Mockito 2.10 `anyString()` no longer matches null values. Use `nullable(Class)` instead.";
}

@Override
public Duration getEstimatedEffortPerOccurrence() {
return Duration.ofMinutes(1);
}

@Nullable
@Override
protected TreeVisitor<?, ExecutionContext> getSingleSourceApplicableTest() {
return new UsesMethod<>(ANY_STRING);
}

@Override
protected TreeVisitor<?, ExecutionContext> getVisitor() {
return new JavaIsoVisitor<ExecutionContext>() {

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext executionContext) {
J.MethodInvocation mi = super.visitMethodInvocation(method, executionContext);

if (ANY_STRING.matches(mi)) {
maybeAddImport("org.mockito.ArgumentMatchers", "nullable", false);
maybeRemoveImport("org.mockito.ArgumentMatchers.anyString");
return getNullableMethodTemplate().withPrefix(mi.getPrefix());
}
return mi;
}
};
}

private static J.MethodInvocation getNullableMethodTemplate() {
return PartProvider.buildPart("import static org.mockito.ArgumentMatchers.nullable;\n" +
"public class A {\n" +
" void method() {\n" +
" Object x = nullable(String.class);\n" +
" }\n" +
"}", J.MethodInvocation.class, MOCKITO_CLASS_PATH);
}
}
14 changes: 14 additions & 0 deletions src/main/resources/META-INF/rewrite/mockito.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ recipeList:
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: org.mockito.MockitoAnnotations.Mock
newFullyQualifiedTypeName: org.mockito.Mock
- org.openrewrite.java.testing.mockito.AnyToNullable
- org.openrewrite.java.ChangeType:
oldFullyQualifiedTypeName: org.mockito.Matchers
newFullyQualifiedTypeName: org.mockito.ArgumentMatchers
Expand Down Expand Up @@ -121,6 +122,19 @@ recipeList:
newVersion: 3.x
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.testing.mockito.AnyToNullable
displayName: Replace Mockito 1.x `any(Class)` and `anyString()` with `nullable(Class)`
description: Since Mockito 2.10 `any(Class)` and `anyString()` no longer match null values. Use `nullable(Class)` instead.
recipeList:
- org.openrewrite.java.ChangeMethodName:
methodPattern: org.mockito.Mockito any(java.lang.Class)
newMethodName: nullable
- org.openrewrite.java.ChangeMethodTargetToStatic:
methodPattern: org.mockito.Mockito nullable(java.lang.Class)
fullyQualifiedTargetTypeName: org.mockito.ArgumentMatchers
- org.openrewrite.java.testing.mockito.AnyStringToNullable
---
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.testing.mockito.ReplacePowerMockito
displayName: Replace Powermock with raw Mockito
description: Replace Powermock with raw Mockito.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright 2021 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.junit.jupiter.api.Test;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.java.JavaParser;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

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

class AnyStringToNullableTest implements RewriteTest {

@Override
public void defaults(RecipeSpec spec) {
spec
.parser(JavaParser.fromJavaVersion()
.classpathFromResources(new InMemoryExecutionContext(), "mockito-core-3.12.4")
.logCompilationWarningsAndErrors(true))
.recipe(new AnyStringToNullable());
}

@Test
void replaceAnyStringWithNullableStringClass() {
//language=java
rewriteRun(
java("""
class Example {
String greet(String name) {
return "Hello " + name;
}
}
"""),
java(
"""
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class MyTest {
void test() {
Example example = mock(Example.class);
when(example.greet(anyString())).thenReturn("Hello world");
}
}
""",
"""
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class MyTest {
void test() {
Example example = mock(Example.class);
when(example.greet(nullable(String.class))).thenReturn("Hello world");
}
}
"""
)
);
}

@Test
void doNotReplaceAnyInt() {
//language=java
rewriteRun(
java("""
class Example {
String greet(int value) {
return "Hello " + value;
}
}
"""),
java(
"""
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.anyInt;

class MyTest {
void test() {
Example example = mock(Example.class);
when(example.greet(anyInt())).thenReturn("Hello 5");
}
}
"""
)
);
}

}