2016-09-30 16 views
0

我想嘲笑通用接口:無法樣機通用接口在JMockit

public interface IModel<T, S> { 
    public S classify(T entity); 
} 

該接口是子類由3具體類:TextModelImageModelScoringModel。每個具體類都有不同的T和S參數。

我寫了收到具體的模型類作爲參數,並生成模型的嘲笑版本的通用方法:

private <T extends IModel<?, ?>> T mockModel(Class<T> modelClass) { 
    return new MockUp<T>() { 
     @Mock public Object classify(Object entity) { return null; } 
    }.getMockInstance(); 
} 

我知道IModel::classify具有通用類型的輸入和輸出兩個,但我還沒有找到在模型中使用實際泛型方法的方法。

調用此方法時,我得到一個IllegalArgumentException

java.lang.IllegalArgumentException異常:類型com.classificationmanager.model價值$ Impl_IModel與COM的返回類型com.classificationmanager.model.TextModel不兼容。 classificationmanager.model.TextModelFactory#createModel(com.classificationmanager.model.ModelDescriptor) 在com.classificationmanager.model.ModelFetcherTest $ 5(ModelFetcherTest.java:110) 在com.classificationmanager.model.ModelFetcherTest.mockAllFactories(ModelFetcherTest.java: 109).......(留給你的餘地)

我認爲獲取和返回一個Object,而不是T和S爲問題,但在取出模擬的方法,只是嘲諷上課的時候,我得到了同樣的異常:

private <T extends IModel<?, ?>> T mockModel(Class<T> modelClass) { 
    return new MockUp<T>() { 
    }.getMockInstance(); 
} 

我可以做一個開關並返回一個具體的類,但這隻會是討厭的。

任何涉及Expectations API的解決方法也適用於我。

10X

+0

爲什麼不使用'@Mocked TextModel'? –

+0

我可以,但後來我不得不模擬ImageModel,ScoringModel和IModel的所有未來具體子類 – KidCrippler

+0

您是不是已經通過調用'mockModel(TextModel.class)'來做到這一點,正如問題中所暗示的那樣? –

回答

1

也許下面的例子可以幫助(雖然我還是不明白的問題 - 在XY問題的可能的情況下)。

public final class ExampleTest { 
    public interface IModel<T, S> { S classify(T entity); } 

    static class TextModel implements IModel<Integer, String> { 
     @Override public String classify(Integer entity) { return "test"; } 
    } 

    static class ImageModel implements IModel<String, Image> { 
     @Override public Image classify(String entity) { return null; } 
    } 

    @Test 
    public void createNonMockedInstanceForAnyModelClass() { 
     IModel<Integer, String> m1 = mockModel(TextModel.class); 
     String s = m1.classify(123); 

     IModel<String, Image> m2 = mockModel(ImageModel.class); 
     Image img = m2.classify("test"); 

     assertEquals("test", s); 
     assertNull(img); 
    } 

    <T extends IModel<?, ?>> T mockModel(Class<T> modelClass) { 
     // Or use newUninitializedInstance in case the model class doesn't 
     // have a no-args constructor. 
     return Deencapsulation.newInstance(modelClass); 
    } 

    @Test 
    public void mockAllModelImplementationClassesAndInstances(
     @Capturing IModel<?, ?> anyModel 
    ) { 
     IModel<Integer, String> m = new TextModel(); 
     String s = m.classify(123); 

     assertNull(s); 
    } 
} 
+0

10倍的答案,'Deencapsulation :: newInstance'方法是一個很好的解決方法,我的問題。在第二次測試中,「Capturing」註釋的字段究竟是幹什麼用的?在測試中我沒有看到任何'anyModel'輸入參數的用法。 – KidCrippler

+0

'@Capturing'將'@ Mocked'的作用擴展到實現/擴展模擬字段/參數(及其實例)的聲明類型的所有類。 –

+0

是的,我知道,但在您提供的測試中,它似乎並不像「TextModel」實例被模擬,它只是調用具體實現並驗證它實際返回null。我錯過了什麼? – KidCrippler