提问人:user1589188 提问时间:11/15/2023 更新时间:11/15/2023 访问量:23
Mockito 在为 InjectMocks 带注释的对象调用 openMocks 后,用新对象替换了已经模拟的对象
Mockito replaced already mocked objects with new ones after calling openMocks for InjectMocks annotated object
问:
我有一个奇怪的情况,即 Mockito 在调用带注释的对象后用新对象替换已经模拟的对象。openMocks()
@InjectMocks
这是我的设置:
@RunWith(MockitoJUnitRunner.class) public class MyTest {
@Mock ClassA mockClassA;
@Mock ClassB mockClassB;
@InjectMocks ClassToTest classToTest;
AutoCloseable closeable;
@Before public void openMocks() {
closeable = MockitoAnnotations.openMocks(this);
}
//...
}
public class ClassToTest {
@Inject private ClassA classA;
private final ClassB classB;
@Inject public ClassToTest(ClassB classB) {
this.classB = classB;
}
}
P.S. 我无法控制,我无法重写它以将私有成员移动到构造函数。ClassToTest
classA
在这里,我想同时嘲笑 和 ,而测试是针对 .由于不是通过构造函数设置的,我需要使用 Mockito 为我设置它。它确实在测试中正确设置了它。classA
classB
ClassToTest
classA
@InjectMocks
mockClassA
但是,问题出在 .我在之前设置了一个断点,在那里我可以看到 = 和 = ,这是预期的。然后调用后,我可以看到 = ,这很好。但现在变成了一个新的模拟对象,不再是了。由于我需要设置 模拟返回 ,因此用新的模拟替换它是行不通的。classB
openMocks()
classToTest.classA
null
classToTest.classB
mockClassB
openMocks()
classToTest.classA
mockClassA
classToTest.classB
mockClassB
mockClassB
有没有办法告诉 Mockito 不要换成新的模拟?classB
答:
@RunWith(MockitoJUnitRunner.class)
应该已经初始化了所有 -and -annotated 字段。@Mock
@InjectMocks
MockitoAnnotations.openMocks
仅当您不使用注释并且必须手动初始化字段时才需要。
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock ClassA mockClassA;
@Mock ClassB mockClassB;
@InjectMocks ClassToTest classToTest;
@Before public void setup() {
when(mockClassB.someCall()).thenReturn(whatever);
}
@Test public void test() {
// use this.classToTest
}
}
通过直接分配字段,可以在没有注释的情况下做到这一点:@Mock
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
ClassA mockClassA = mock(ClassA.class);
ClassB mockClassB = mock(ClassB.class);
@InjectMocks ClassToTest classToTest;
@Before public void setup() {
when(mockClassB.someCall()).thenReturn(whatever);
}
@Test public void test() {
// use this.classToTest
}
}
或
public class MyTest {
ClassA mockClassA = mock(ClassA.class);
ClassB mockClassB = mock(ClassB.class);
@InjectMocks ClassToTest classToTest;
AutoCloseable closeable;
@Before public void setup() {
closeable = MockitoAnnotations.openMocks(this);
when(mockClassB.someCall()).thenReturn(whatever);
}
@Test public void test() {
// use this.classToTest
}
}
或者,手动创建所有模拟对象,并使用反射来分配被测类的字段。
当然,将类设计为可测试的类总是值得的,这意味着它们的依赖项是通过构造函数传递的。
这类似于为什么在执行单元测试时未调用我的模拟方法?(对两个不同模拟对象的不同引用,测试引用一个对象,类引用另一个模拟对象)。
评论
MockitoJUnitRunner
classA
classToTest
openMocks()
classA
MockitoJUnitRunner
classA
mockClassA
openMocks
ClassA
ClassB
mock()
多亏了 @knittl 的想法,我最终得到了这个完善的解决方案:
//@RunWith(MockitoJUnitRunner.class) no need
public class MyTest {
@Mock ClassA mockClassA;
ClassB mockClassB = mock(ClassB.class);
@InjectMocks ClassToTest classToTest = new ClassToTest(mockClassB);
AutoCloseable closeable;
@Before public void openMocks() {
closeable = MockitoAnnotations.openMocks(this);
}
//...
}
评论