2015-03-31 165 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