2014-02-25 15 views
1

比方說,我有如下的界面我想嘲笑:如何處理模擬對象中的差異?

Searcher.java

public interface Searcher { 

    public String search(); 

    public void someMethod(); 

} 

我該怎麼辦時,我想使用不同的模擬實現這個接口?例如,在一個測試中,我想讓search()方法返回空字符串,在另一個測試中,我希望它開始執行一些HTTP請求等。

我是否封裝了行爲,如fx。該接口將它放在一個SearchBehaviour接口,然後編寫實現:

public class SearcherMock implements Searcher { 

    private SearchBehaviour searchBehaviour; 

    public SearcherMock(SearchBehaviour searchBehaviour) { 
     this.searchBehaviour = searchBehaviour; 
    } 

    @Override 
    public String search() { 
     return searchBehaviour.search(); 
    } 

    @Override 
    public void someMethod() { 
     // Do something here 
    } 

} 

還是我創建一個新的模擬類爲每個模擬實現,重孰輕? FX。 EmptySearcherHTTPSearcher

+0

單元測試的HTTP請求?聽起來很腥,因爲你的界面(不會拋出任何異常;如果請求失敗怎麼辦?) – fge

+0

不要說HTTP部分,它只是用來說明變化 –

+1

我不認爲你想這樣做;真正的模擬不會運行復雜的代碼。你會讓它返回你想要的值,以便可以測試該模擬的_users_。也就是說,用mockito你可以在搜索時搜索(search)搜索(),然後返回(「某事」); – fge

回答

3

我會建議你使用Java嘲弄的工具,如jMockMockito這將一定時間節省您不是讓你自己寫的樣機工具,而不是寫很好的樣機:)

使用你的Mockito可以做這樣的事情(儘管未測試):

import static org.mockito.Mockito.*; 

Searcher mockedEmptySearcher = mock(Searcher.class); 

// define how empty searcher should behave 
when(mockedList.search()).thenReturn(""); 
2

記住,你可以自由地爲不同的測試創建匿名內部類,而無需使用庫:

@Test public void test1() { 
    // When referring to outside local variables, they must be final. 
    final AtomicBoolean someMethodCalled = new AtomicBoolean(false); 

    Searcher fakeSearcher = new Searcher() { 
    @Override public String search() { 
     return "stubbed return value"; 
    } 

    @Override public void someMethod() { 
     someMethodCalled.set(true); 
    }  
    }; 
    SystemUnderTest systemUnderTest = new SystemUnderTest(fakeSearcher); 
    systemUnderTest.pressBigRedButton(); 
    assertTrue("someMethod should have been called", someMethodCalled.get()); 
} 

即使獲得是相當聰明:

private Searcher createFakeSearcher(final String... searchResults) { 
    return new Searcher() { 
    int returnIndex = 0; 

    @Override public String search() { 
     return searchResults[returnIndex++]; 
    } 

    @Override public void someMethod() {}  
    }; 
} 

但一段時間投入學習嘲弄的框架將竭誠爲您和您的測試很好,因爲喜歡的Mockito框架被設計爲奪走那些樣板:

// Uses static imports from org.mockito.Mockito; 
@Test public void test1() { 
    Searcher mockSearcher = mock(Searcher.class); 
    when(mockSearcher.search()) 
     .thenReturn("search one") 
     .thenReturn("search two") 
     .thenThrow(new IllegalStateException()); 

    SystemUnderTest systemUnderTest = new SystemUnderTest(mockSearcher); 
    systemUnderTest.pressBigRedButton(); 
    verify(mockSearcher, times(2)).someMethod(); 
} 

爲了更好地概念性介紹測試加倍(假人/存根/嘲笑/假貨)和它們之間的差異,讀Martin Fowler's article here,或潛水右入Mockito documentation

2

您可以使用Mockito等模擬框架,並使用JUnitParams對您的測試進行參數化。

假設您有一個驗證搜索者的類,並且如果搜索返回「有效」,它將會通過。代碼和測試如下所示,包含2個測試用例,1個用於有效,另一個用於無效搜索結果。

public class SomeClass { 
    public boolean isValid(Searcher searcher) { 
     return searcher.search().equals("valid"); 
    } 
} 

@RunWith(JUnitParamsRunner.class) 
public class SomeClassTest { 

    public Object[] provideIsValid() { 
     return new Object[]{ 
       new Object[]{ "invalid", false }, 
       new Object[]{ "valid", true } 
     }; 
    } 

    @Test 
    @Parameters(method = "provideIsValid") 
    public void testIsValid(String output, String expected) { 
     SomeClass someClass = new SomeClass(); 
     Searcher mock = mock(Searcher.class); 
     when(mock.search()).thenReturn(output); 

     String actual = someClass.isValid(mock); 
     assertEquals(expected, actual); 
    } 
+0

OP,請注意JUnit4有一個內置的[參數化](http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html)跑步者,但是[JUnitParams](https:// code。 google.com/p/junitparams/)確實提供了更多功能。要麼你會問這種變化。 –