【问题标题】:Using Mockito for HTTP Client将 Mockito 用于 HTTP 客户端
【发布时间】:2015-06-30 19:44:40
【问题描述】:

我有一个存根的 JSON OBJECT,但需要使用 Mockito 模拟以下内容:

HttpResponse response = defaultHttpClient.execute(postRequest);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuilder result = new StringBuilder();
while ((line = rd.readLine()) != null) {
    result.append(line);        
}
JSONObject jsonResponseObject = new JSONObject(result.toString()); 

我创建了以下 Mocks:

@Mock
    private HttpClient mockHttpClient;
    private HttpPost mockHttpPost;
    private HttpResponse mockHttpResponse;
    private HttpEntity mockHttpEntity; 
    private InputStream mockInputStream;
    private InputStreamReader mockInputStreamReader;
    private BufferedReader mockBufferedReader;

并有以下when 语句:

    Mockito.when(mockHttpClient.execute(mockHttpPost)).thenReturn(mockHttpResponse); 
    Mockito.when(mockHttpResponse.getEntity()).thenReturn(mockHttpEntity);
    Mockito.when(mockHttpEntity.getContent()).thenReturn(mockInputStream);

问题:我是否需要创建所有这些“何时”语句,如果是,那么我需要创建哪些其他语句才能访问存根 JSON?

有什么建议吗?

谢谢

【问题讨论】:

  • 请添加更多代码,以便我们能够准确理解模拟对象
  • 你是否在使用像 Spring MVC 这样的 Web 框架?

标签: java json mocking mockito


【解决方案1】:

可能必须模拟 HttpClientHttpResponse,如果它们是接口(尽管根据您的库,您可以使用 MockHttpClientMockHttpResponse),但是您不应该嘲讽别的东西。

为什么?

模拟是在我们无法具体化的类上建立预期的输出行为,或者更确切地说,是我们希望为这个特定的测试实例以某种方式表现的类。您希望确保从模拟 HttpClient 得到正确的响应,并且当调用 response.getEntity() 时,它会返回一个有意义的 HttpEntity。您可以选择是否模拟它;我个人不会,因为模拟不会添加任何额外的值(除了可能验证是否调用了特定方法)。

其他一切都是具体的实现 - 您应该允许其他对象与之前模拟的元素的结果进行交互,以确保它们的行为与没有模拟时一样。

实际上...除非您将它们传递或以某种方式注入它们,否则您真的无法模拟它们。我强烈不鼓励您尝试在该方法中模拟任何 newed 对象。

你没有具体说明你在断言什么,但我希望它在某种程度上是你的JSONObject。我会断言您希望放入其中的内容实际上已放入 JSON 对象,并验证您的模拟对象是否以您期望的方式被调用和调用。

顺便说一句,您的注释@Mock 不是级联的-您必须用@Mock 注释所有模拟字段,然后用@RunWith(MockitoJunitRunner.class) 注释测试类,或者使用MockitoAnnotation.initMocks(this)(一个或另一个;两者都不是必需的,除非在极端情况下)。如果您选择注解,请不要忘记测试对象上的@InjectMocks

最后,您的 when 条件符合我的预期 - 应该没问题。

【讨论】:

    【解决方案2】:

    是的,您可能需要您提到的所有 when 语句。 但是,您可以只返回new ByteArrayInputStream( "{foo : 'bar'}".getBytes() ),而不是返回mockInputStream

    最后,您可以验证 json 响应对象是否有一个值为 'bar' 的 'foo' 属性。

    也就是说,我不确定给定的方法是否值得测试 - 因为它所做的一切都是打开流和读取数据。

    【讨论】:

      【解决方案3】:

      首先了解Mocking的含义。

      1)为什么我们需要模拟?

      假设我们不想调用任何原始方法,并且希望我们应该调用一个虚拟方法而不是那个原始方法,那么我们应该去模拟。

      例如:

      Mockito.when(mockHttpClient.execute(mockHttpPost)).thenReturn(mockHttpResponse)
      

      这意味着无论何时调用此execute(),您都将返回您自己准备好的值,而不是原始的mockHttpResponse

      因此,在您的情况下,准备您的存根对象并在需要时进行模拟。 在这里你准备你的回应(注意实际但虚拟)。

      mockHttpResponse.setEntity(new Entity());
      mockHttpResponse.getEntity().setContent('{yourJsonString}');
      

      所以每当你的

        mockHttpClient.execute(mockHttpPost); //will be called
      

      然后它将返回您在测试方法中手动准备的响应。

      当你控制时

        new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
      

      然后当response.getEntity().getContent() 被调用时你会得到{yourJsonString} 并让其余代码完成它的功能。最后,您的 JSON 存根对象将准备就绪。

      请记住,测试用例只是为开发人员提供帮助。我们可以模拟任何东西并返回任何东西或任何存根对象。我们只需编写测试用例,通过传递预期值和非预期值来检查我们的控制流。

      这将使您的工作变得轻松。现在您想使用它来模拟您的 BufferReader 类。

       BufferedReader bufferedReader = org.mockito.Mockito.mock(BufferedReader.class); 
       when(bufferedReader.readLine()).thenReturn("first line").thenReturn("second line");
      
       org.junit.Assert.when(new Client(bufferedReader).parseLine()).thenEquals(IsEqual.equalTo("1"));
      

      【讨论】:

      • 嗨Shoaib,感谢您的澄清!不确定这里需要做什么,但我试图避免进行实际的 HttpClient 调用,因为我有来自该调用的响应的最终处理(解析)版本,这是我已存根的 JSON 对象。请指教..谢谢
      • 这很有帮助。但正如我在上面的问题中提到的,当调用 HttpResponse response = defaultHttpClient.execute(postRequest) 时,我返回一个 mockHttpResponse 。但是在实际方法中,我必须执行 3 个步骤才能返回 JSON 对象。所以,如果我在 response.getEntity().getContent() 运行时返回存根的 JSON 对象,那么当我的原始方法中的后续语句运行时,这不是问题吗?请指教..
      • 点击此链接了解更多详情。我只是解释你想模拟,何时模拟休息取决于你的观点。 stackoverflow.com/questions/19626609/…
      猜你喜欢
      • 2012-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多