2015-03-31 163 views
9

你知道如何物理地模擬Elasticsearch Java客戶端嗎?目前嘲笑Java中的下列要求:如何模擬Elasticsearch Java客戶端?

SearchResponse response = client.prepareSearch(index) 
       .setTypes(type) 
       .setFrom(0).setSize(MAX_SIZE) 
       .execute() 
       .actionGet(); 
SearchHit[] hits = response.getHits().getHits(); 

我嘲笑:

  • client.prepareSearch
  • SearchRequestBuilder:
    • builder.execute
    • builder.setSize
    • builder.setFrom
    • builder.setTypes
  • SearchResponse:
    • action.actionGet
  • SearchResponse:
    • response.getHits
    • searchHits.getHits

所以我的測試看起來像:

SearchHit[] hits = ..........; 

SearchHits searchHits = mock(SearchHits.class); 
when(searchHits.getHits()).thenReturn(hits); 

SearchResponse response = mock(SearchResponse.class); 
when(response.getHits()).thenReturn(searchHits); 

ListenableActionFuture<SearchResponse> action = mock(ListenableActionFuture.class); 
when(action.actionGet()).thenReturn(response); 

SearchRequestBuilder builder = mock(SearchRequestBuilder.class); 
when(builder.setTypes(anyString())).thenReturn(builder); 
when(builder.setFrom(anyInt())).thenReturn(builder); 
when(builder.setSize(anyInt())).thenReturn(builder); 
when(builder.execute()).thenReturn(action); 

when(client.prepareSearch(index)).thenReturn(builder); 

醜...... 所以我想已知如果有更多的「優雅的方式」來嘲笑這個代碼。

感謝

+1

對於它的價值,我認爲你太低級了。你只應該測試**你的**代碼,而不是檢查Elasticsearch是否工作:假設它是。所以我想你有一個包裝所有這些代碼的方法:例如'public String [] search(searchParams ..){SearchResponse response = client.prepareSearch(index).. etc; SearchHit [] hits = response.getHits()。getHits();返回擊中; }'。你的測試應該嘲笑你的搜索方法,並返回不同輸入的模擬String []結果。 – 2015-03-31 13:10:05

回答

2

我遇到類似的問題嘲諷建設者的時候,所以我想我會嘗試看看是否有更好的方式。

正如Spoon先生所說,如果您可以避免這樣做,那麼可能會更好,因爲它不是您的代碼,並且可以假設爲「正常工作」,但我仍然認爲我會放棄它。

我已經想出了一個(也許是粗略的)通過在Mockito中使用「默認答案」的方法。我還在決定我是否喜歡它。

這裏是我的建設者......

public class MyBuilder { 

    private StringBuilder my; 

    public MyBuilder() { 
     my = new StringBuilder(); 
    } 

    public MyBuilder name(String name) { 
     my.append("[name=").append(name).append("]"); 
     return this; 
    } 

    public MyBuilder age(String age) { 
     my.append("[age=").append(age).append("]"); 
     return this; 
    } 

    public String create() { 
     return my.toString(); 
    } 
} 

(漂亮的基本權利?)

我得到了我的測試是這個樣子......

// Create a "BuilderMocker" (any better name suggestions welcome!) 
    BuilderMocker<MyBuilder> mocker = BuilderMocker.forClass(MyBuilder.class); 
    // Get the actual mock builder 
    MyBuilder builder = mocker.build(); 

    // expect this chain of method calls... 
    mocker.expect().name("[NAME]").age("[AGE]"); 

    // expect this end-of-chain method call... 
    Mockito.when(builder.create()).thenReturn("[ARGH!]"); 

現在,如果我這樣做以下...

System.out.println(builder.name("[NAME]").age("[AGE]").create()); 

...我希望輸出「[ARGH!]」。

如果我改變了最後一行......

System.out.println(builder.name("[NOT THIS NAME]").age("[AGE]").create()); 

...然後我希望它打破NullPointerException。

下面是實際的「BuilderMocker」 ......

import static org.mockito.Mockito.mock; 
import static org.mockito.Mockito.when; 
import static org.mockito.Mockito.withSettings; 

import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class BuilderMocker<T> { 

    private Class<T> clazz; 
    private T recorder; 
    private T mock; 

    // Create a BuilderMocker for the class 
    public static <T> BuilderMocker<T> forClass(Class<T> clazz) { 
     return new BuilderMocker<T>(clazz); 
    } 

    private BuilderMocker(Class<T> clazz) { 
     this.clazz = clazz; 
     this.mock = mock(clazz); 
     createRecorder(); 
    } 

    // Sets up the "recorder" 
    private void createRecorder() { 
     recorder = mock(clazz, withSettings().defaultAnswer(new Answer<Object>() { 

      @Override 
      public Object answer(InvocationOnMock invocation) throws Throwable { 
       // If it is a chained method... 
       if (invocation.getMethod().getReturnType().equals(clazz)) { 
        // Set expectation on the "real" mock... 
        when(invocation.getMethod().invoke(mock, invocation.getArguments())).thenReturn(mock); 
        return recorder; 
       } 
       return null; 
      } 

     })); 
    } 

    // Use this to "record" the expected method chain 
    public T expect() { 
     return recorder; 
    } 

    // Use this to get the "real" mock... 
    public T build() { 
     return mock; 
    } 
} 

不知道是否有在做的Mockito本的「內置」的方式,但是這似乎工作。

+0

我喜歡這種方法。我應該把我的建設者作爲圖書館來開發,並在我的測試中重用這些類。謝謝! – 2015-06-25 08:08:18