2016-06-08 88 views
2

我有兩個類:模擬繼承的最終方法

public class BaseClass <T> { 
    private final T config; 
    ... 
    @NotNull 
    public final T getConfig() { 
    return config; 
    } 
} 

public class DerivedClass extends BaseClass<MyConfig> { 
    ... 
} 

和測試:

... 
MyConfig myConfig = mock(MyConfig.class); 
DerivedClass child = mock(DerivedClass.class); 
when(child.getConfig()).thenReturn(myConfig); // this line generates the error 

我得到一個錯誤,getConfig()被返回null,而不是myConfig。我還有其他方法調用相同的模擬對象與預期的時間/返回模式,所以我玩弄了多態性。當我刪除了方法的最後限制並在派生類中覆蓋它(只是調用超級版本)時,模擬工作正常。

我不想爲產品測試重新設計產品代碼並降低API的剛性,因此上面的繼承更改不是可接受的解決方案。我怎樣才能調出超類的方法?

+0

「模擬繼承的方法」 - 你總是可以做出關於其出身粗魯的評論,但是這不會是政治上正確的(對不起,couldn」不要抵制標題:-) –

回答

4

Mockito's FAQ

什麼的的Mockito的限制?
[...]

  • 不能嘲笑最後的方法 - 沒有任何異常,執行他們的實際行爲。 Mockito無法警告你嘲笑最後的方法,所以要提高警惕。

[...]

對於這一點,你需要像PowerMock的延伸。有關工作示例,請參閱this question。一個完整的描述可以在PowerMock's documentation

+1

提示:至少應該提到** PowerMock **有很多缺點。我絕不會把它推薦給另一個沒有良好劑量的人,「通常你根本不應該使用它」。 – GhostCat

0

不幸的是,你不能嘲笑最後的方法。但一個警告:轉向PowerMock是不是這個問題的答案。相反:轉向PowerMock意味着進入一個不應該在沒有經過精心準備的情況下進入的領域。

PowerMock操縱你的字節碼,允許你重載最終或靜態方法。這意味着它會讓你接觸到各種奇怪而奇怪的問題;往往沒有理由;但是很可能會浪費大量時間來尋找與您的代碼無關的「bug」。 PowerMock的另一個大問題是,它使大多數「覆蓋」框架無用(因爲這些框架還操縱字節碼......)

所以在你的情況下:實際上,使該方法最終成爲好設計。因爲這強調了Open/closed principle。所以,從概念上分,有兩個選項「修理」這樣的:

a)您提供了一個受保護的構造採取「配置」允許該「配置」對象(例如依賴注入)

二)你還記得FCoI,避免做基類/子類的事完全

+0

Bertrand Meyer(「開放 - 封閉」原則的創造者)寫道(我現在似乎無法找到它,對不起)對於程序設計語言(如C++),默認情況下方法不可覆蓋(非虛擬)或者甚至允許方法是「最終」的,因爲這會阻止OCP的應用。所以,雖然它*是一個很好的設計,使得方法和類成爲final,但它完全不強調OCP。相反,它強調GoF的「偏好構成而非繼承」原則。 –

+0

如果您無意阻止子類覆蓋某種方法,您如何關閉**修改**的類? OCP的典型用例是當你有一個抽象基類提供一個或多個要調用的最終方法時......它們自己調用抽象方法。如果這些方法不是最終的,你可以在子類上改變這種行爲。 – GhostCat

+0

事實上,不,在OCP(正如Meyer的書和[Robert Martin的文章](https://www.cs.duke.edu/courses/fall07/cps108/papers/ocp.pdf)中所描述的) 「封閉」僅僅是一種已投入生產的產品,因此不應該因違反客戶代碼而受到修改。請注意這是作者所說的;我發現這個原則完全錯誤和過時。在OCP作者看來,一個類應該保持「可擴展性」,也就是說,它不應該被聲明爲final,也不應該將它的任何非'private'方法聲明爲'final'。 –