![](/img/trans.png)
[英]Verify if inherited super class method was called from method being tested or not
[英]How to verify whether a super class method was called in Spock?
想象一下,我有以下類結構:
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
所暗示的那樣,合同是一個覆蓋,對超類方法的委托是可選的。 為什么要強制用戶調用超類方法? 但正如蒂姆所說,您可以測試對您很重要的副作用。 這是一個小例子,一個副作用是字段分配,另一個是寫入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"
}
}
更新:您想要做的事情在技術上是不可能的,原因是:它會破壞封裝,請參閱此處,此處,間接也此處。 該方法被覆蓋,這個詞說明了一切。 測試方法的(副作用)或結果,而不是它的交互(它實際上被調用)。 盡管 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()
添加一個無操作實現。
tim_yates 和 kriegaex 是叢林中的大野獸,當談到 Spock 的好壞時,或者一般的 TDD 式測試......他們不止一次(正確地)以他們在這里的方式挑選我的問題,基本上是在測試代碼而不是實現的基礎。
雖然有時很難。 也許在某些情況下,您想要測試super.doSomething()
的調用。 我只是使用 TDD 組合在一起,已經完成了一個“尖峰”,我在沒有測試的情況下沖進了一個TreeTableView
的編輯器。 在這里可以看到“尖峰”。 在對我的回答的建設性評論中,kleopatra 建議我檢查(即在應用程序代碼中放置一個if
)以確保super.startEdit()
在繼續之前確實開始編輯單元格,所以在這種情況下它是不足以測試super.startEdit()
的“副作用”,因為isEditing()
現在返回true
。 你真的需要知道你的類的startEdit()
實際上只是調用super.startEdit()
。
但是,我不相信它可以做到,並且 tim_yates 或 kriegaex 幾乎肯定會說如果可能的話,您將如何做到這一點。
因此,我建議的 TDD 解決方案是這樣的:
def 'super start edit should be called if cell is not empty'(){
given:
// NB has to be GroovySpy because isEmpty() is final
DueDateEditor editor = GroovySpy( DueDateEditor ){
isEmpty() >> false
}
when:
editor.startEdit()
then:
1 * editor.callSuperStartEdit()
}
class DueDateEditor extends TreeTableCell {
@Override
void startEdit(){
if( ! isEmpty() ) {
// this is the line you have to add to make the test pass
callSuperStartEdit()
}
}
def callSuperStartEdit(){
super.startEdit()
}
}
我認為您必須“產生”一種人工的單一用途方法,因為完全沒有副作用!
PS 我實際上會參數化這個測試,以便它在第二次調用中返回true
給isEmpty()
,並要求在這種情況下不調用該方法。
我從未使用過 Spock 框架,但我認為您可以使用運算符或反射的實例檢查 Parent.method 中的實例類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.