我正在尝试测试一个方法,该方法在内部调用父类的受保护方法(外部依赖)。
考虑这个简化的例子:
public class Parent {
protected void parentAction() {
System.out.println("Parent action");
}
}
public class Child extends Parent {
private final Runnable backupAction;
private final Runnable normalAction;
public Child(Runnable backupAction, Runnable normalAction) {
this.backupAction = backupAction;
this.normalAction = normalAction;
}
public void childAction() {
try {
super.parentAction();
} catch (Exception exc) {
this.backupAction.run();
return;
}
this.normalAction.run();
}
}
我想测试一下,在异常情况下,会调用备份操作,而正常情况下则不会 - 使用
verify()
这很容易。前提是模拟 super.parentAction()
抛出异常。
这个答案不适用于我的用例,因为父类是外部依赖项,我无权访问该包(我无法在测试文件夹中创建相同的包)。
考虑到您必须遵循的约束,我认为一种选择可能是创建特定于测试的实现来覆盖
parentAction
以覆盖特定的用例。
class ChildTest {
private Runnable normalAction = Mockito.mock(Runnable.class);
private Runnable backupAction = Mockito.mock(Runnable.class);
@Test
public void shouldUseNormalWhenNoExceptionThrown() {
Child child = new Child(normalAction, backupAction) {
@Override
protected void parentAction() throws Exception {
System.out.println("invoked");
}
};
child.childAction();
Mockito.verify(normalAction).run();
Mockito.verify(backupAction, never()).run();
}
@Test
public void shouldUseBackupWhenExceptionThrown() {
Child child = new Child(normalAction, backupAction) {
@Override
public void childAction() {
super.childAction();
}
@Override
protected void parentAction() throws Exception {
throw new Exception();
}
};
child.childAction();
Mockito.verify(backupAction).run();
Mockito.verify(normalAction, never()).run();
}
}
请注意,这需要更改您的
Child
类以避免调用 super.parentAction()
,而只使用 parentAction()
来代替 – 否则它将始终调用 Parent
中的方法而不是测试中的实现:
public void childAction() {
try {
parentAction();
this.normalAction.run();
} catch (Exception e) {
this.backupAction.run();
}
}
作为替代方案,您可以使用 PowerMock 来模拟受保护的方法:
@RunWith(PowerMockRunner.class)
@PrepareForTest({Child.class})
class ChildTest {
private Runnable normalAction = Mockito.mock(Runnable.class);
private Runnable backupAction = Mockito.mock(Runnable.class);
@Test
public void shouldUseNormalWhenNoExceptionThrown() throws Exception {
Child child = PowerMockito.spy(new Child(normalAction, backupAction));
PowerMockito.doNothing().when(child, "parentAction", new Object[] {});
child.childAction();
Mockito.verify(normalAction).run();
Mockito.verify(backupAction, never()).run();
}
@Test
public void shouldUseBackupWhenExceptionThrown() throws Exception {
Child child = PowerMockito.spy(new Child(normalAction, backupAction));
doThrow(new Exception()).when(child, "parentAction");
child.childAction();
Mockito.verify(backupAction).run();
Mockito.verify(normalAction, never()).run();
}
}
但是,请注意,如果您使用的是 JDK17+,则需要向编译器指定额外的参数 - 请参阅Powermock 与 JDK 17 的兼容性