From 64d3e9bf5e48ef4585ec8f903db7bfac0e68dec7 Mon Sep 17 00:00:00 2001 From: lingenj Date: Mon, 11 Nov 2024 11:48:38 +0100 Subject: [PATCH] - Introduce `NoInitializationForInjectMock` and use it in mockito.yml - Let easymock apply MockitoBestPractices --- .../NoInitializationForInjectMock.java | 59 +++++++++++++++++ .../resources/META-INF/rewrite/easymock.yml | 1 + .../resources/META-INF/rewrite/mockito.yml | 1 + .../NoInitializationForInjectMockTest.java | 63 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java create mode 100644 src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java diff --git a/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java b/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java new file mode 100644 index 000000000..e209950f4 --- /dev/null +++ b/src/main/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMock.java @@ -0,0 +1,59 @@ +/* + * Copyright 2021 the original author or authors. + *

+ * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.AnnotationMatcher; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.service.AnnotationService; +import org.openrewrite.java.tree.J; + +import java.util.stream.Collectors; + +public class NoInitializationForInjectMock extends Recipe { + + private static final AnnotationMatcher INJECT_MOCKS = new AnnotationMatcher("@org.mockito.InjectMocks"); + + @Override + public String getDisplayName() { + return "Remove initialization when using @InjectMocks"; + } + + @Override + public String getDescription() { + return "Removes unnecessary initialization for fields annotated with @InjectMocks in Mockito tests."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check(new UsesType<>("org.mockito.*", false), new JavaIsoVisitor() { + @Override + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations variableDeclarations, ExecutionContext ctx) { + J.VariableDeclarations vd = super.visitVariableDeclarations(variableDeclarations, ctx); + + if (new AnnotationService().matches(getCursor(), INJECT_MOCKS)) { + return vd.withVariables(vd.getVariables().stream().map(var -> var.withInitializer(null)).collect(Collectors.toList())); + } + + return vd; + } + }); + } +} diff --git a/src/main/resources/META-INF/rewrite/easymock.yml b/src/main/resources/META-INF/rewrite/easymock.yml index 8b17bc18f..5df42ffeb 100644 --- a/src/main/resources/META-INF/rewrite/easymock.yml +++ b/src/main/resources/META-INF/rewrite/easymock.yml @@ -128,6 +128,7 @@ recipeList: oldFullyQualifiedTypeName: org.easymock.TestSubject newFullyQualifiedTypeName: org.mockito.InjectMocks # - com.todo.openrewrite.java.easymock.RefactorEasyMockIArgumentMatcherIntoMockitoArgumentMatcher + - org.openrewrite.java.testing.mockito.MockitoBestPractices - org.openrewrite.java.dependencies.AddDependency: groupId: org.mockito artifactId: mockito-core diff --git a/src/main/resources/META-INF/rewrite/mockito.yml b/src/main/resources/META-INF/rewrite/mockito.yml index dc569f5e0..90cb1d3fb 100644 --- a/src/main/resources/META-INF/rewrite/mockito.yml +++ b/src/main/resources/META-INF/rewrite/mockito.yml @@ -151,6 +151,7 @@ recipeList: - org.openrewrite.java.ChangeType: oldFullyQualifiedTypeName: org.mockito.runners.MockitoJUnitRunner newFullyQualifiedTypeName: org.mockito.junit.MockitoJUnitRunner + - org.openrewrite.java.testing.mockito.NoInitializationForInjectMock - org.openrewrite.java.testing.mockito.CleanupMockitoImports - org.openrewrite.java.testing.mockito.MockUtilsToStatic - org.openrewrite.java.testing.junit5.MockitoJUnitToMockitoExtension diff --git a/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java b/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java new file mode 100644 index 000000000..c60f197e3 --- /dev/null +++ b/src/test/java/org/openrewrite/java/testing/mockito/NoInitializationForInjectMockTest.java @@ -0,0 +1,63 @@ +package org.openrewrite.java.testing.mockito; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +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 NoInitializationForInjectMockTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .parser(JavaParser.fromJavaVersion() + .classpathFromResources(new InMemoryExecutionContext(), "junit-jupiter-api-5.9", "mockito-junit-jupiter-3.12", "mockito-core-3.12")) + .recipe(new NoInitializationForInjectMock()); + } + + @Test + @DocumentExample + void removeInitializationOfInjectMocks() { + //language=java + rewriteRun( + java( + """ + class MyObject { + private String someField; + + public MyObject(String someField) { + this.someField = someField; + } + } + """ + ), + java( + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InjectMocks; + import org.mockito.junit.jupiter.MockitoExtension; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @InjectMocks + MyObject myObject = new MyObject("someField"); + } + """, + """ + import org.junit.jupiter.api.extension.ExtendWith; + import org.mockito.InjectMocks; + import org.mockito.junit.jupiter.MockitoExtension; + + @ExtendWith(MockitoExtension.class) + class MyTest { + @InjectMocks + MyObject myObject; + } + """ + ) + ); + } +}