2012-11-13 99 views
55

構造函數我有如下的類:模擬與參數

public class A { 
    public A(String test) { 
     bla bla bla 
    } 

    public String check() { 
     bla bla bla 
    } 
} 

的邏輯構造A(String test)check()是我試圖嘲弄的事情。我想要任何呼叫,如:new A($$$any string$$$).check()返回一個虛擬字符串"test"

我想:

A a = mock(A.class); 
when(a.check()).thenReturn("test"); 

String test = a.check(); // to this point, everything works. test shows as "tests" 

whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk); 
// also tried: 
//whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk); 

new A("random string").check(); // this doesn't work 

但它似乎並不奏效。 new A($$$any string$$$).check()仍在通過構造函數邏輯,而不是獲取A的模擬對象。

+0

正在你的嘲笑檢查()方法嗎? –

+0

@BenGlasser check()工作正常。只是whenNew看起來不起作用。我也更新了描述。 – Shengjie

回答

56

的代碼,你發佈的作品,我有和的Mockito的Powermockito最新版本。也許你沒有準備好A? 試試這個:

A.java

public class A { 
    private final String test; 

    public A(String test) { 
     this.test = test; 
    } 

    public String check() { 
     return "checked " + this.test; 
    } 
} 

MockA.java

import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.equalTo; 
import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 

import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Mockito; 
import org.powermock.api.mockito.PowerMockito; 
import org.powermock.core.classloader.annotations.PrepareForTest; 
import org.powermock.modules.junit4.PowerMockRunner; 

@RunWith(PowerMockRunner.class) 
@PrepareForTest(A.class) 
public class MockA { 
    @Test 
    public void test_not_mocked() throws Throwable { 
     assertThat(new A("random string").check(), equalTo("checked random string")); 
    } 
    @Test 
    public void test_mocked() throws Throwable { 
     A a = mock(A.class); 
     when(a.check()).thenReturn("test"); 
     PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a); 
     assertThat(new A("random string").check(), equalTo("test")); 
    } 
} 

兩個測試應該通過與1.9.0的Mockito,powermockito 1.4.12和JUnit 4.8.2

+13

另請注意,如果構造函數是從另一個類中調用的,請將其包含在「PrepareForTest」列表中 –

33

據我所知,你不能用mockito模擬構造函數,只能使用方法。但根據Mockito谷歌代碼頁上的維基,有一種方法可以通過在您的類中創建一個返回該類的新實例的方法來模擬構造函數的行爲。那麼你可以嘲笑這種方法。下面是一個excerpt directly from the Mockito wiki

模式1 - 使用一個線方法創建對象

要使用模式1(試驗一種名爲MyClass的類),你將取代像

Foo foo = new Foo(a, b, c); 
通話

Foo foo = makeFoo(a, b, c); 

和寫一行實現方法具d

Foo makeFoo(A a, B b, C c) { 
     return new Foo(a, b, c); 
    } 

重要的是,在方法中不包含任何邏輯;只是創建 對象的一行。其原因是該方法本身永遠不會被 單元測試。

當你來測試這個類時,你測試的對象實際上是一個Mockito間諜,用這個方法重寫,返回一個 模擬。因此,你正在測試的不是這個類本身,而是它的一個稍微修改過的版本。

您的測試類可能包含成員一樣

@Mock private Foo mockFoo; 
    private MyClass toTest = spy(new MyClass()); 

最後,測試方法裏面你模擬出調用 makeFoo與像

doReturn(mockFoo) 
     .when(toTest) 
     .makeFoo(any(A.class), any(B.class), any(C.class)); 

線您可以使用更多的匹配具體比任何()如果你想 檢查傳遞給構造函數的參數。

如果你只是想返回你的類的模擬對象,我認爲這應該適合你。在任何情況下,你可以在此處詳細瞭解嘲諷對象的創建:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

+10

+1,我不喜歡我需要調整我的源代碼使其更適合mockito。感謝分享。 – Shengjie

+15

在編寫代碼時,讓源代碼更易於測試,或避免可測試性反模式,這絕對不錯。如果您編寫的源代碼更易於測試,則該代碼自動更易於維護。在自己的方法中分離構造函數調用只是實現這一點的一種方法。 –

8

沒有使用Powermock ....看到下面的例子基於Ben Glasser的答案,因爲它花了我一些時間來弄清楚..hope節省了一些時間...

原班:

public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(new BClazz(cClazzObj, 10)); 
    } 
} 

修改的類:

@Slf4j 
public class AClazz { 

    public void updateObject(CClazz cClazzObj) { 
     log.debug("Bundler set."); 
     cClazzObj.setBundler(getBObject(cClazzObj, 10)); 
    } 

    protected BClazz getBObject(CClazz cClazzObj, int i) { 
     return new BClazz(cClazzObj, 10); 
    } 
} 

測試類

public class AClazzTest { 

    @InjectMocks 
    @Spy 
    private AClazz aClazzObj; 

    @Mock 
    private CClazz cClazzObj; 

    @Mock 
    private BClazz bClassObj; 

    @Before 
    public void setUp() throws Exception { 
     Mockito.doReturn(bClassObj) 
       .when(aClazzObj) 
       .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt()); 
    } 

    @Test 
    public void testConfigStrategy() { 
     aClazzObj.updateObject(cClazzObj); 

     Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj); 
    } 
} 
1

具有的Mockito測試的侷限性最終,STA抽動和私人方法。

與jMockit測試庫,你可以做一些東西非常容易和直接的,如下:一java.io.File類的

模擬構造函數:

new MockUp<File>(){ 
    @Mock 
    public void $init(String pathname){ 
     System.out.println(pathname); 
     // or do whatever you want 
    } 
}; 
  • 公共構造名稱應替換爲$ init
  • 拋出的參數和異常保持不變
  • 返回類型應定義爲void

模擬一個靜態方法:

  • 刪除方法模擬簽名
  • 方法簽名靜態保持相同,否則