I am using Mockito 5.20.0 to mock a static method, but the mock is not correctly closing / the mocked behavior is leaking outside of the tests it is intended to apply to. This is only a problem if MyMockedTest runs before MyUnmockedTest. If MyUnmockedTest runs first, there is no problem and both test classes pass. From what I can tell, the try-with-resources should be closing and un-mocking MyUtil when MyMockedTest::testStuff is complete, and the mocked behavior should not carry over to another class.
I have run the tests both in IntelliJ and with ./gradlew clean build test. The tests do not run in parallel.
Illustrative example code with details redacted, hopefully it communicates the gist of what's going on:
public class MyUtil {
public static DBConnection getMyDbConnection() {
// ....
// The other code here makes a network call
return new DBConnection();
}
}
import org.mockito.MockedStatic;
import static org.mockito.Mockito.*;
public class MyMockedTest {
@ParameterizedTest
@EnumSource(value = Source.class, names = {"SOURCE_ONE", "SOURCE_TWO"})
public void testStuff() {
// MyUtil has several methods called, and I only want to change the behavior of
// getMyDbConnection.
try (MockedStatic<MyUtil> myUtilMockedStatic = mockStatic(MyUtil.class, CALLS_REAL_METHODS)) {
DBConnection dbConnection = mock(DBConnection.class);
when(dbConnection.getConnectionName()).thenReturn("myConnection");
myUtilMockedStatic.when(MyUtil::getMyDbConnection).thenReturn(redshiftConnection);
// MyUtil.getMyDbConnection() is called downstream in code under test
MyFirstClass myFirstClass = new MyFirstClass();
DBConnection results = myFirstClass.getDbConnection()
// Assertion passes
assertEquals(results.getDbConnection().getConnectionName(), "myConnection");
}
}
}
public class MyUnmockedTest {
@ParameterizedTest
@EnumSource(value = Source.class, names = {"SOURCE_ONE", "SOURCE_TWO"})
public void testStuffWithoutMockedUtils() {
MyOtherClass myOtherClass = new MyOtherClass();
// MyUtil.getMyDbConnection() is called downstream in code under test
DBConnection results = myOtherClass.getDbConnection();
// Assertion fails, because the downstream MyUtil.getMyDbConnection() is still returning the mocked DBConnection.
assertNotEquals(results.getDbConnection().getConnectionName(), "myConnection");
}
}
Relevant build.gradle Test configuration:
test {
useJUnitPlatform {
includeEngines "jqwik", "junit-jupiter"
}
include "**/*Test.class"
}
configurations {
mockitoAgent
}
dependencies {
// ...
testImplementation "org.junit.jupiter:junit-jupiter-api:6.0.1"
testImplementation "org.junit.jupiter:junit-jupiter-params:6.0.1"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:6.0.1"
testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.13.4"
testImplementation "net.jqwik:jqwik:1.9.3"
testImplementation "org.wiremock:wiremock:3.13.1"
testImplementation "org.mockito:mockito-core:5.20.0"
testImplementation "org.mockito:mockito-junit-jupiter:5.20.0"
mockitoAgent("org.mockito:mockito-core:5.20.0") {
transitive = false
}
// ...
}
tasks {
test {
jvmArgs += "-javaagent:${configurations.mockitoAgent.asPath}"
}
}
test {
environment "ENVIRONMENT", "test"
testLogging {
exceptionFormat = 'full'
showStandardStreams = true
events "passed", "skipped", "failed"
}
}