2012-05-26 28 views
5

我使用JUnit +的Mockito測試等的方法編寫單元測試:懲戒在抽象類的公共方法的調用,而不需要繼承抽象類,使用的Mockito prefererably

public someObject methodUnderTest(){ 
    SomeObject obj = SomeAbstractClass.someMethod(); 

    if(obj!=null){ 
    obj.someOtherMethod(); 
    } 

    return someThing; 
} 

而且我想嘲笑在上面的代碼段中提到abstract Class "SomeAbstractClass"呼叫,所以我可以覈實「OBJ」如呼叫:

verify(SomeAbstractClass).someMethod(); 
verify(obj).someOtherMethod(); 

我已經使用類似特徵的Mockito嘗試: Mockito.CALLS_REAL_METHODS 的Mockito。 RETURNS_MOCKS

但由於SomeAbstractClass不具備的依賴性,它們不起作用。

注意:

1)SomeObject是一個接口。

2)我需要一種技術來測試上面的代碼片段。我受限於使用上面的代碼片段,並且不能更改代碼片段。

回答

1

假設:如果你寫單元測試,我猜你仍然可以修改測試過的方法。

解決方案:

  1. 提取靜態方法調用重寫的方法:
public someObject methodUnderTest() { 
    SomeObject obj = getSomeObject(); 

    if(obj!=null){ 
     obj.someOtherMethod(); 
    } 

    return someThing; 
} 

protected SomeObject getSomeObject() { 
    return SomeAbstractClass.someMethod(); 
} 
  1. 那麼你可以使用的Mockito間諜以部分嘲笑的對象,你實際測試:
private ClassUnderTest classUnderTest; 

@Before 
public void setUp() { 
    classUnderTest= new ClassUnderTest(); 
    classUnderTest = Mockito.spy(classUnderTest); 
} 

@Test 
public void test() { 
    SomeObject someObject = Mockito.mock(SomeObject.class); 
    when(classUnderTest.getSomeObject()).thenReturn(someObject); 
    classUnderTest.methodUnderTest(); 
    verify(someObject).someOtherMethod(); 
} 

@Test 
public void testNull() { 
    when(classUnderTest.getSomeObject()).thenReturn(null); 
    classUnderTest.methodUnderTest(); 
    verify(something); 
} 
+0

感謝miheys的幫助。我完全一樣。 –

1

使用匿名類:

public interface SomeObject { 
    public Object someOtherMethod(); 
} 

public abstract class SomeAbstractClass { 
    abstract SomeObject someMethod(); 
} 

@Test 
public void test() { 
    SomeAbstractClass target = new SomeAbstractClass() { 
     SomeObject someMethod() { 
      // some impl 
      SomeObject someObject = new SomeObject() { 
       public Object someOtherMethod() { 
        // some other impl 
       } 
      }; 
      return someObject; 
     } 
    }; 

    // now test target 
} 
+0

感謝波希米亞人,但我忘了提到SomeObject返回的是一個接口以及「SomeAbstractClass.someMethod()」是一個公共和靜態的方法。因此,我不得不實現Interface「SomeObject」,我不想這樣做,「SomeAbstractClass」和「SomeObject」都是我在我的Web應用程序中使用的第三方庫的一部分。 –

+0

您也可以爲接口使用匿名類(如SomeObject) - 請參閱編輯答案 – Bohemian

2

您可以使用PowerMock嘲笑靜態和最後方法。

2

這聽起來像問題是,你的CALLS_REAL_METHODS的使用被應用到整個班級,在那裏你真的想模擬出具體的方法(即做一個「部分模擬」)。您可以選擇使用CALLS_REAL_METHODS,然後專門嘲諷你需要調用這裏有兩個選擇,一是使用thenCallRealMethod,以及一個:

public void testMethodUnderTest_mockSpecificThings() { 
    SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    when(myAbstractClass.someMethod()).thenReturn(foo); 
    when(myAbstractClass.methodUnderTest()).thenCallRealMethod(); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

public void testMethodUnderTest_makeSpecificRealCalls() { 
    SomeAbstractClass myAbstractClass = 
     Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS); 
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class); 
    // overrides the default answer 
    when(myAbstractClass.someMethod()).thenReturn(myObject); 

    myAbstractClass.methodUnderTest(); 

    verify(myAbstractClass).someMethod(); 
    verify(myObject).someOtherMethod(); 
} 

預先警告您SomeAbstractClass從未實際實例,因此,如果您在抽象類依賴於任何行爲構造函數,就像變量初始化一樣 - 包括聲明字段的內聯初始化 - 您需要自己明確地創建這些調用。