Skip to content

Commit

Permalink
Ensure Jmockit expectations with no times or result transform to a mo…
Browse files Browse the repository at this point in the history
…ckito verify
  • Loading branch information
shivanisky authored and timtebeek committed Jun 19, 2024
1 parent f67d1e9 commit 5042d5f
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.tree.*;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -118,21 +119,25 @@ private void rewriteMethodBody(List<Statement> expectationStatements) {
return;
}
J.MethodInvocation invocation = (J.MethodInvocation) expectationStatements.get(0);
if (!mockInvocationResults.getResults().isEmpty()) {
boolean hasExpectationsResults = !mockInvocationResults.getResults().isEmpty();
if (hasExpectationsResults) {
// rewrite the statement to mockito if there are results
rewriteExpectationResult(mockInvocationResults.getResults(), invocation);
} else if (nextStatementCoordinates.isReplacement()) {
// if there are no results and the Expectations block is not yet replaced, remove it
removeExpectationsStatement();
}

// TODO doesn't cover cases with multiple times eg minTimes and maxTimes - this is typically rare scenario
if (mockInvocationResults.getTimes() != null) {
writeMethodVerification(invocation, mockInvocationResults.getTimes(), "times");
}
if (mockInvocationResults.getMinTimes() != null) {
} else if (mockInvocationResults.getMinTimes() != null) {
writeMethodVerification(invocation, mockInvocationResults.getMinTimes(), "atLeast");
}
if (mockInvocationResults.getMaxTimes() != null) {
} else if (mockInvocationResults.getMaxTimes() != null) {
writeMethodVerification(invocation, mockInvocationResults.getMaxTimes(), "atMost");
} else if (!hasExpectationsResults) {
// no times, no results
writeMethodVerification(invocation, null, null);
}
}

Expand Down Expand Up @@ -182,18 +187,22 @@ private void removeExpectationsStatement() {
methodBody.getStatements().get(bodyStatementIndex + numStatementsAdded).getCoordinates().after();
}

private void writeMethodVerification(J.MethodInvocation invocation, Expression times, String verificationMode) {
private void writeMethodVerification(J.MethodInvocation invocation, @Nullable Expression times, @Nullable String verificationMode) {
String fqn = getInvocationSelectFullyQualifiedClassName(invocation);
if (fqn == null) {
// cannot write a verification statement for an invocation without a select field
return;
}
visitor.maybeAddImport("org.mockito.Mockito", "verify");
visitor.maybeAddImport("org.mockito.Mockito", verificationMode);
if (verificationMode != null) {
visitor.maybeAddImport("org.mockito.Mockito", verificationMode);
}

List<Object> templateParams = new ArrayList<>();
templateParams.add(invocation.getSelect());
templateParams.add(times);
if (times != null) {
templateParams.add(times);
}
templateParams.add(invocation.getName().getSimpleName());

String verifyTemplate = getVerifyTemplate(invocation.getArguments(), fqn, verificationMode, templateParams);
Expand Down Expand Up @@ -251,17 +260,20 @@ private static void appendToTemplate(StringBuilder templateBuilder, boolean buil
templateBuilder.append(templateField);
}

private static String getVerifyTemplate(List<Expression> arguments, String fqn, String verificationMode, List<Object> templateParams) {
private static String getVerifyTemplate(List<Expression> arguments, String fqn, @Nullable String verificationMode, List<Object> templateParams) {
StringBuilder templateBuilder = new StringBuilder("verify(#{any(" + fqn + ")}"); // verify(object
if (verificationMode != null) {
templateBuilder.append(", " + verificationMode + "(#{any(int)})"); // verify(object, times(2)
}
templateBuilder.append(").#{}("); // verify(object, times(2)).method(

if (arguments.isEmpty()) {
return "verify(#{any(" + fqn + ")}, "
+ verificationMode
+ "(#{any(int)})).#{}();";
templateBuilder.append(");"); // verify(object, times(2)).method();
return templateBuilder.toString();
}
StringBuilder templateBuilder = new StringBuilder("verify(#{any(" + fqn + ")}, "
+ verificationMode
+ "(#{any(int)})).#{}(");

boolean hasArgument = false;
for (Expression argument : arguments) {
for (Expression argument : arguments) { // verify(object, times(2).method(anyLong(), any Int()
if (argument instanceof J.Empty) {
continue;
} else if (argument instanceof J.Literal) {
Expand All @@ -276,7 +288,7 @@ private static String getVerifyTemplate(List<Expression> arguments, String fqn,
if (hasArgument) {
templateBuilder.delete(templateBuilder.length() - 2, templateBuilder.length());
}
templateBuilder.append(");");
templateBuilder.append(");"); // verify(object, times(2).method(anyLong(), any Int());
return templateBuilder.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void defaults(RecipeSpec spec) {

@DocumentExample
@Test
void voidResult() {
void whenNoResultNoTimes() {
//language=java
rewriteRun(
java(
Expand All @@ -71,6 +71,55 @@ void test() {
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class MyTest {
@Mock
Object myObject;
void test() {
myObject.wait(10L, 10);
verify(myObject).wait(anyLong(), anyInt());
}
}
"""
)
);
}

@DocumentExample
@Test
void whenNoResultNoTimesNoArgs() {
//language=java
rewriteRun(
java(
"""
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit5.JMockitExtension;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(JMockitExtension.class)
class MyTest {
@Mocked
Object myObject;
void test() {
new Expectations() {{
myObject.wait();
}};
myObject.wait(10L, 10);
}
}
""",
"""
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class MyTest {
Expand All @@ -79,6 +128,7 @@ class MyTest {
void test() {
myObject.wait(10L, 10);
verify(myObject).wait();
}
}
"""
Expand Down Expand Up @@ -585,6 +635,73 @@ void test() {
);
}

@Test
void whenNoArguments() {
//language=java
rewriteRun(
java(
"""
import java.util.List;
class MyObject {
public String getSomeField() {
return "X";
}
}
"""
),
java(
"""
import java.util.ArrayList;
import java.util.List;
import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit5.JMockitExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.junit.jupiter.api.Assertions.assertNull;
@ExtendWith(JMockitExtension.class)
class MyTest {
@Mocked
MyObject myObject;
void test() {
new Expectations() {{
myObject.getSomeField();
result = null;
}};
assertNull(myObject.getSomeField());
}
}
""",
"""
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MyTest {
@Mock
MyObject myObject;
void test() {
when(myObject.getSomeField()).thenReturn(null);
assertNull(myObject.getSomeField());
}
}
"""
)
);
}

@Test
void whenMixedArgumentMatcher() {
//language=java
Expand Down Expand Up @@ -989,6 +1106,7 @@ void test() {
assertNull(myOtherObject.getSomeObjectField());
myObject.wait(10L, 10);
assertEquals("foo", myOtherObject.getSomeStringField("bar", 10L));
verify(myObject).wait(anyLong(), anyInt());
}
}
"""
Expand Down

0 comments on commit 5042d5f

Please sign in to comment.