In my scenario, I have a simple class with a method returning a String:
public class Foo {
public String bar() {
return "1";
}
}
For simplification, a List will store instances of Foo (in real life project, this is some kind of a factory/cache combination):
public class FooCache {
private static List<Foo> cache = new ArrayList<>();
public static Foo getOrCreateFoo(Foo foo) {
if (cache.isEmpty()) {
cache.add(foo);
}
return cache.get(0);
}
}
My junit 5 test will fail as soon as I try to reassign the return value of Foo#bar in different test scenarios:
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class FooTest {
@Mock
private Foo foo;
@Test
void firstTest() {
// Arrange
when(foo.bar()).thenReturn("2");
// Act
Foo uut = FooCache.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("2", actual);
}
@Test
void secondTest() {
// Arrange
when(foo.bar()).thenReturn("3"); // <--- HAS NO EFFECT ON CACHED FOO
// Act
Foo uut = FooCache.getOrCreateFoo(foo);
String actual = uut.bar();
// Assert
assertEquals("3", actual); // fails with 3 not equals 2
}
}
First test method firstTest finishes with success, foo returns "2" and foo is now stored in the cache list.
Second test method secondTest fails with "2 does not equal 3", since
when(foo.bar()).thenReturn("3")
will change the behavior of foo, but has no effect on the mocked object in the cache which will be used calling FooCache#getOrCreateFoo.
Why is that the case and is there any way I can change a mocked object behavior after is got stored in a list outside the test class?