模拟抽象 class 并使用 Mockito 注释注入 classes?
Mocking an abstract class and injecting classes with Mockito annotations?
是否可以同时模拟抽象 class 并使用 Mockito 注释将其注入模拟的 classes。我现在的情况是:
@Mock private MockClassA mockClassA;
@Mock private MockClassB mockClassB;
@Mock(answer = Answers.CALLS_REAL_METHODS) private AbstractClassUnderTest abstractClassUnderTest;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
Whitebox.setInternalState(abstractClassUnderTest, mockClassA);
Whitebox.setInternalState(abstractClassUnderTest, mockClassB);
}
我想在 AbstractClassUnderTest 上使用类似 @InjectMocks 的东西,但它不能与 @Mock 结合使用。目前的情况,使用 Powermock 的 Whitebox 是可行的,但我很好奇是否可以只用注释来解决它。我找不到任何解决方案或示例。
(我知道有人反对测试抽象 classes,我个人宁愿测试一个具体的实现,只使用 @InjectMocks。)
出于一个明确的原因,我不知道有什么方法可以解决这个问题:@InjectMocks 适用于 non-mocked 正在测试的系统,@Mock 适用于模拟协作者,Mockito 不是设计的对于任何 class 在同一测试中担任这两个角色的人。
请记住,您的 @Mock(CALLS_REAL_METHODS)
声明是 :您正在测试您的 AbstractClassUnderTest,但您不是 运行 任何构造函数或初始化任何字段。我不认为你可以期望使用这种设计的测试是现实的或健壮的,不管注释能为你做什么或不能做什么。 (就我个人而言,我之前赞成抽象 classes 的真实部分模拟作为 "tool in the toolbox",但我开始认为它们与现实相去甚远而无用。)
如果我处于你的位置,我会创建一个小的覆盖实现来进行测试:
@RunWith(JUnit4.class) public class AbstractClassTest {
/** Minimial AbstractClass implementation for testing. */
public static class SimpleConcreteClass extends AbstractClass {
public SimpleConcreteClass() { super("foo", "bar", 42); }
@Override public void abstractMethod1() {}
@Override public String abstractMethod2(int parameter) { return ""; }
}
@InjectMocks SimpleConcreteClass classUnderTest;
@Mock mockClassA;
@Mock mockClassB;
}
至此,您有了一个简单且可预测的 AbstractClass 实现,如果您只是想测试 AbstractClass 是否具有与之前相同的 API 扩展功能,则即使没有模拟框架也可以使用它。 (这是对抽象 classes 的 often-overlooked 测试。)您甚至可以提取它,因为它可能对其他测试有用:是否要覆盖单个测试的抽象行为 class,您可以创建一个匿名内部 class,只需一个方法覆盖,或者您可以设置 classUnderTest = spy(classUnderTest);
来设置 Mockito 代理和您想要的行为。
(请记住,@InjectMocks 和@Spy 不能可靠地一起使用,如 this GitHub issue 和它链接到的 Google 代码和邮件列表线程中所述。)
我在初始化之前发现了一些模拟字段的技巧。
@InjectMocks
private AbstractClass abstractClass;
@Mock
private MockClass mockClass;
@Before
public void init() {
abstractClass= mock(AbstractClass.class, Answers.CALLS_REAL_METHODS);
MockitoAnnotations.initMocks(this);
}
也许它会对某人有所帮助。
是否可以同时模拟抽象 class 并使用 Mockito 注释将其注入模拟的 classes。我现在的情况是:
@Mock private MockClassA mockClassA;
@Mock private MockClassB mockClassB;
@Mock(answer = Answers.CALLS_REAL_METHODS) private AbstractClassUnderTest abstractClassUnderTest;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
Whitebox.setInternalState(abstractClassUnderTest, mockClassA);
Whitebox.setInternalState(abstractClassUnderTest, mockClassB);
}
我想在 AbstractClassUnderTest 上使用类似 @InjectMocks 的东西,但它不能与 @Mock 结合使用。目前的情况,使用 Powermock 的 Whitebox 是可行的,但我很好奇是否可以只用注释来解决它。我找不到任何解决方案或示例。
(我知道有人反对测试抽象 classes,我个人宁愿测试一个具体的实现,只使用 @InjectMocks。)
出于一个明确的原因,我不知道有什么方法可以解决这个问题:@InjectMocks 适用于 non-mocked 正在测试的系统,@Mock 适用于模拟协作者,Mockito 不是设计的对于任何 class 在同一测试中担任这两个角色的人。
请记住,您的 @Mock(CALLS_REAL_METHODS)
声明是
如果我处于你的位置,我会创建一个小的覆盖实现来进行测试:
@RunWith(JUnit4.class) public class AbstractClassTest {
/** Minimial AbstractClass implementation for testing. */
public static class SimpleConcreteClass extends AbstractClass {
public SimpleConcreteClass() { super("foo", "bar", 42); }
@Override public void abstractMethod1() {}
@Override public String abstractMethod2(int parameter) { return ""; }
}
@InjectMocks SimpleConcreteClass classUnderTest;
@Mock mockClassA;
@Mock mockClassB;
}
至此,您有了一个简单且可预测的 AbstractClass 实现,如果您只是想测试 AbstractClass 是否具有与之前相同的 API 扩展功能,则即使没有模拟框架也可以使用它。 (这是对抽象 classes 的 often-overlooked 测试。)您甚至可以提取它,因为它可能对其他测试有用:是否要覆盖单个测试的抽象行为 class,您可以创建一个匿名内部 class,只需一个方法覆盖,或者您可以设置 classUnderTest = spy(classUnderTest);
来设置 Mockito 代理和您想要的行为。
(请记住,@InjectMocks 和@Spy 不能可靠地一起使用,如 this GitHub issue 和它链接到的 Google 代码和邮件列表线程中所述。)
我在初始化之前发现了一些模拟字段的技巧。
@InjectMocks
private AbstractClass abstractClass;
@Mock
private MockClass mockClass;
@Before
public void init() {
abstractClass= mock(AbstractClass.class, Answers.CALLS_REAL_METHODS);
MockitoAnnotations.initMocks(this);
}
也许它会对某人有所帮助。