Mockito深度对象Mock:如何无需Getter实现属性方法Mock
Got it, let's tackle this Mockito problem you're facing. The core issue is: when using @Mock A a;, directly calling when(a.list.isEmpty()).thenReturn(true) throws an error because the list field is null on the mocked A instance. Using @Mock(answer = Answers.RETURNS_DEEP_STUBS) fixes the null issue but forces you to use getter methods, which you don't want to add everywhere.
Here are practical workarounds that let you stub the list's behavior without adding getters:
1. Manually Mock the List and Set It via Reflection
You can create a mock for List<B> separately, then use reflection to assign this mock to the list field of your mocked A instance. This bypasses the need for getters entirely.
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.lang.reflect.Field; import java.util.List; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class YourTestClass { @Mock A a; @Mock List<B> mockList; @BeforeEach void setUp() throws NoSuchFieldException, IllegalAccessException { // Access the private/protected list field in class A Field listField = A.class.getDeclaredField("list"); listField.setAccessible(true); // Assign the mock list to the field listField.set(a, mockList); // Now you can stub the list's methods directly when(mockList.isEmpty()).thenReturn(true); } @Test void yourTest() { assert(a.list.isEmpty()); // This will return true as stubbed } }
2. Use Spring's ReflectionTestUtils (If You're in a Spring Project)
If your project uses Spring, ReflectionTestUtils simplifies the reflection boilerplate, making the code cleaner and more readable:
import org.springframework.test.util.ReflectionTestUtils; // ... other imports @ExtendWith(MockitoExtension.class) public class YourTestClass { @Mock A a; @Mock List<B> mockList; @BeforeEach void setUp() { // Set the mock list into A's field with a single method call ReflectionTestUtils.setField(a, "list", mockList); when(mockList.isEmpty()).thenReturn(true); } }
3. Spy a Real A Instance (If A Can Be Instantiated)
If A has a default constructor or can be easily instantiated, you can spy on a real A object instead of mocking it entirely. Then replace its list field with your mock list:
import org.mockito.Spy; // ... other imports @ExtendWith(MockitoExtension.class) public class YourTestClass { @Spy A a = new A(); // Spy on a real A instance @Mock List<B> mockList; @BeforeEach void setUp() throws NoSuchFieldException, IllegalAccessException { Field listField = A.class.getDeclaredField("list"); listField.setAccessible(true); listField.set(a, mockList); when(mockList.isEmpty()).thenReturn(true); } }
All these approaches let you stub the list field's behavior without modifying your original A and B classes to add getters. Pick the one that fits your project setup best!
内容的提问来源于stack exchange,提问作者vinzzz

