想象一下我具有以下类结构:
class Parent {
public void method() {
// Some calculations
}
}
class Child extends Parent {
@Override
public void method() {
super.method();
// Some additional logic
}
}
我正在对Child.method
进行Spock测试,并想验证是否从Parent.method
中调用了Child.method
。我做了一些研究,但还没有找到令人满意的解决方案来解决我的问题。
如何在Spock测试中验证在Child.method
的调用中还调用了超类方法(Parent.method
)?
已知的解决方案:在Child
中,将super.method()
移至单独的程序包专用方法。
我想知道是否有更好的解决方案。
tim_yates评论:
您为什么要对此进行测试?您不知道是在执行超类计算吗?
我完全同意。我不会进行测试,因为正如@Override
所暗示的那样,合同是一个替代,委托给超类方法是可选的。为什么要强迫用户调用超类方法?但是正如Tim所说,您可以测试对您很重要的副作用。这是一个小例子,一个副作用是字段分配,另一个副作用是写入System.out
的内容(可能很愚蠢,但只是为了显示模拟中不明显的内容):
package de.scrum_master.stackoverflow.q60167623;
public class Parent {
protected String name;
public void method() {
// Some calculations
System.out.println("parent method");
name = "John Doe";
}
}
package de.scrum_master.stackoverflow.q60167623;
class Child extends Parent {
@Override
public void method() {
super.method();
// Some additional logic
System.out.println("child method");
}
public static void main(String[] args) {
new Child().method();
}
}
package de.scrum_master.stackoverflow.q60167623
import spock.lang.Specification
class ChildTest extends Specification {
static final PrintStream originalSysOut = System.out
PrintStream mockSysOut = Mock()
def setup() {
System.out = mockSysOut
}
def cleanup() {
System.out = originalSysOut
}
def test() {
given:
def child = new Child()
when:
child.method()
then:
1 * mockSysOut.println({ it.contains("parent") })
child.name == "John Doe"
}
}
更新:从技术上讲,您仅想做的事情是不可能的,原因是:这会破坏封装,请参见here,here,也间接地参见here。方法是overridden,这句话说明了一切。测试方法的(副作用)或结果,而不是方法的交互作用(实际上称为方法)。即使Spock手册警告某些地方规格过高,Spock的交互测试功能也被过度使用。它只会使您的测试变脆。对于诸如发布/订阅(观察者模式)之类的设计模式而言,交互测试是可以的,在这种模式下测试对象之间的交互是有意义的。
Parent
中的某些功能,则应通过设计而不是测试来强制执行。abstract class Parent {
public final void method() {
// Some calculations
additionalLogic();
}
protected abstract void additionalLogic();
}
class Child extends Parent {
@Override
protected void additionalLogic() {
super.method();
// Some additional logic
}
}
您当然不能将其设为abstract
,而只是为additionalLogic()
添加一个无操作实现。