-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
mockStatic of enum class is unstable - impacted by earlier use of the class (unrelated to mockStatic) #2183
Comments
I think Mockito don't refresh the enum after calling mockStatic if it was aready loaded |
Could you clarify that you mean by that? I checked if Mockito.clearAllCaches() works. It wasn't working. |
Actualy I prefexed all my testes that use mockStatic like : xxxxWithStaticMockTest.java
|
Hey @arivaldh , could you share the exception/stack trace? I'm wondering if |
I tried to replicate your issue using:
but didn't succeed to reproduce the described behavior. Are you using I got your run test running by simplifying it: package com;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.mockito.MockedStatic;
import static com.MyEnum.A_VALUE;
import static com.MyEnum.B_VALUE;
import static com.MyEnum.C_VALUE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class MyFactoryClassWithEnumTest {
@Order(0)
@Test
void aTest() {
MyFactoryClass factory = MyFactoryClass.create();
assertThat(factory.valuesVisible()).isEqualTo(new MyEnum[] {
A_VALUE,
B_VALUE,
C_VALUE
});
factory.switchEval(A_VALUE);
}
@Order(1)
@Test
void bTest() {
MyEnum mockInstance = mock(MyEnum.class);
try (MockedStatic<MyEnum> mockedDropType = mockStatic(MyEnum.class)) {
mockedDropType.when(MyEnum::values).thenReturn(new MyEnum[] {
A_VALUE,
B_VALUE,
C_VALUE,
mockInstance
});
MyFactoryClass factory = MyFactoryClass.create();
assertThat(factory.valuesVisible()).isEqualTo(new MyEnum[] {
A_VALUE,
B_VALUE,
C_VALUE,
mockInstance
});
MyEnum myEnum = factory.switchEval(mockInstance);
assertThat(myEnum).isEqualTo(mockInstance);
}
}
} (I modified your Another way to write this test would be to use your suggestion:
We can do exactly that by creating a package com;
public enum MyEnum {
A_VALUE,
B_VALUE,
C_VALUE,
D_VALUE
} and the test: package com;
import org.junit.jupiter.api.Test;
import static com.MyEnum.A_VALUE;
import static com.MyEnum.B_VALUE;
import static com.MyEnum.C_VALUE;
import static com.MyEnum.D_VALUE;
import static org.assertj.core.api.Assertions.assertThat;
class MyFactoryClassWithoutMockTest {
@Test
void cTest() {
MyFactoryClass factory = MyFactoryClass.create();
assertThat(factory.valuesVisible()).isEqualTo(new MyEnum[] {
A_VALUE,
B_VALUE,
C_VALUE,
D_VALUE });
MyEnum myEnum = factory.switchEval(D_VALUE);
assertThat(myEnum).isEqualTo(D_VALUE);
}
} |
Execution :
|
I encountered the samed problem while mocking an Enum and found a workaround by moving the test that contains the MockedStatic call in an inner static class. This cause isolation of the test and doesn't interfere with other tests. Not a solution, just a workaround... |
Still struggling with the same issue. Inner static class was not helping at all to us unfortunately. |
Same issue reproduced on Linux and Win10, surfireplugin 2.22.2 java15. The solution/workaround bdjelaili commented on Jan13 helped me to overcome. |
Java: OpenJDK-18 (18.0.1), language level 11 Test: @Test
@Order(value = 10)
@SuppressWarnings(value = "ResultOfMethodCallIgnored")
@DisplayName(value = "Case 10 :: Testing a login process with started process and unknown step (coverage only)")
void givenInitLogin_whenLoginAlreadyStartedAndUnknownStep_thenExpectedAppropriateException() {
//arrange
final var nonexistentLoginStep = "NONEXISTENT";
final var loginStepEnums = LoginStepsEnum.values();
final var loginStepEnumsAdd = new LoginStepsEnum[loginStepEnums.length + 1];
final var nonexistentLoginStepEnum = mock(LoginStepsEnum.class);
when(nonexistentLoginStepEnum.ordinal()).thenReturn(loginStepEnums.length);
System.arraycopy(loginStepEnums, 0, loginStepEnumsAdd, 0, loginStepEnums.length);
...
//act&assert
try (MockedStatic<LoginStepsEnum> loginStepEnum = Mockito.mockStatic(LoginStepsEnum.class)) {
loginStepEnumsAdd[loginStepEnums.length] = nonexistentLoginStepEnum;
loginStepEnum.when(LoginStepsEnum::values).thenReturn(loginStepEnumsAdd);
loginStepEnum.when(() -> LoginStepsEnum.of(nonexistentLoginStep)).thenReturn(nonexistentLoginStepEnum);
assertThrows(IllegalArgumentException.class, () -> authorizationService.initLogin(credentialsModel));
}
} Enum: enum LoginStepsEnum {
STEP_1, STEP_2, STEP_3, STEP_4
} Service code: ...
final var processStep = LoginStepsEnum.of(processStepStr);
if (processStep == null) {
throw new CustomerException(...);
}
switch (processStep) {
case STEP_1:
...
case STEP_2:
...
case STEP_3:
...
case STEP_4:
...
default:
throw new IllegalArgumentException("Invalid value for Login step");
}
... If I run just this single test, it's success, no any problems.
|
Does anyone know how to implement the temporary workaround provided by @bdjelaili using Gradle? |
Hello I'm adding an enum value to test the default behaviour a a switch statement. would be nice to have someone looking at it. Here is some simplified code for my enum
and the test
|
From an answer to a question on StackOverflow:
This may be another option to workaround the problem, provided that it's possible to control the order of tests. |
OS: Windows 10
Mockito: 3.7.0
JUnit5: 5.7.0
Java: 8 (8u202)
We have two tests. A and B. When run in the order [B, A] they pass. When run in the order [A, B] B fails.
Failure is related to "switch" java statement with enum usage.
While classes are as simple as possible:
MyFactoryClass is the class that should return in (here absent) method "of" appropriate object related to enum value.
We want to test "default" scenario (if someone would be so nice to "override" our enum by his own enum by injecting it "earlier" in the classpath, or just when there's an incompatibility somewhere along the line).
Obviously if there's a better way to test such a scenario, we could change our approach accordingly.
The text was updated successfully, but these errors were encountered: