2017-07-28 109 views
1

我想測試一個類(使用Jukito和Mockito),不幸的是它擴展了另一個類,它有一個靜態方法調用。有可能以某種方式跳過這個電話嗎?我寧願不使用PowerMockito。Jukito/Mockito靜態方法測試

public class A extends B { 

    @Inject 
    public A(final String s){ 
     super(s); 
    } 
} 

public abstract class B { 

    private String s; 

    protected String m = C.get().createUniqueId(); //Exception is thrown here 

    public B(String s){ 
     this.s = s; 
    } 
} 

public class C { 
    private static C c; //assume this is never null 

    public static C get() { 
     return c; 
    } 

    public final native String createUniqueId() {} 

} 

@RunWith(JukitoRunner.class) 
public class ATest { 

    @Inject 
    A a; 

    @Test 
    public void onMethod1Test(){ 
    } 
} 

當運行ATEST,我得到以下錯誤:

Error injecting constructor, java.lang.UnsatisfiedLinkError: C

我以爲這是因爲一個靜態方法的,是我錯了嗎?

請注意,所有的類都只是我真正的類的例子,C類不是我寫的,不能更改(不幸的是)。但是我的課程背後的想法是一樣的,我只是改了名字,只留下了相關的部分。

回答

1

Jukito claims

The combined power of JUnit, Guice and Mockito.

不過的事情是:沒有這些產品可以讓你模擬靜態方法。

唯一能夠做到的框架:PowerMock(ito)和JMockit。

正如您已經解釋過的那樣:通常只需編寫可測試代碼(即避免靜態調用)即可「繞過」這個「缺陷」。但是,由於無法改進設計,因此只有以下兩種選擇:使用PowerMock(ito)來測試此類 - 或者不對其進行測試。

+0

即使我知道所有這些,我想我希望我錯過了一些東西。由於我不太喜歡使用PowerMockito並且不能重寫C類,因此此時我不會測試我的課程。我會接受你的答案,因爲你花時間寫一個簡單的解釋。 – CrazySabbath

0

因此,我們的目標是使用CB的任何新實例上生成m。你不控制C,你試圖找出如何測試它,對吧?我認爲你必須選擇你的毒藥,但我可以爲你的情況考慮另一種「毒藥」的選擇。

B添加靜態字段,給它更多的訪問,則原本是適當的:

public abstract class B { 
    static C c = C.get(); 
    private String s; 
    protected String m = c.createUniqueId(); 
    public B(String s){ 
    this.s = s; 
    } 
} 

現在,您可以重新分配B.c在你的測試嘲笑實例。我對JUnit和Spock更加熟悉,所以我會試着弄清楚它的機制。由於單元測試與它們正在測試的類位於同一個包中,因此可以使用包私有範圍。如果AB不在一個包中,那麼您必須將其升級至protected。這很快且容易,但是讓您可以重新分配其他代碼B.c。您必須判斷該風險是否根本不會測試A

您也可以考慮添加類和接口以從AB中完全隱藏C。從本質上講,你可以創建類似BFactory的產品,其中包含Supplier<String>以生成m。在單元測試中,你嘲笑供應商,在生產中使用基於C的實現。我所能想到的任何方式都是混亂的,或者不會強制B的每個子類以相同的方式生成m。唯一的例外是,如果它實際上使用合成更有意義並且在A上放置B的實例。那麼你可能有一個體面的方式來做到這一點。