无法阅读 Mocked Java.io.Reader

Can't read Mocked Java.io.Reader

我想用 Mockito 测试以下代码:

public static String funcToTest(String query) throws Exception {
    String url = Config.getURL(serviceName);
    HttpClient client = new HttpClient();
    HttpMethod method = new GetMethod(url);
    String resultantString= "";

    method.setQueryString(URIUtil.encodeQuery(query));
    client.executeMethod(method);
    if (method.getStatusCode() == HttpStatus.SC_OK) {
        Reader reader = new InputStreamReader(method
                    .getResponseBodyAsStream());
        int charValue = 0;
        StringBuffer sb = new StringBuffer(1024);
        while ((charValue = reader.read()) != -1) {
            sb.append((char) charValue);
        }
        resultantString = sb.toString();
    }
    method.releaseConnection();
    return resultantString;
}

我创建了如下测试:

@Test
public void testFunc() throws Exception{
    HttpMethod method =  Mockito.mock(HttpMethod.class);
    InputStream inputStream = Mockito.mock(InputStream.class);
    Reader reader = Mockito.mock(Reader.class);

    when(method.getResponseBodyAsStream()).thenReturn(inputStream);
    PowerMockito.whenNew(Reader.class).withArguments(eq(inputStream)).thenReturn(reader);

    Mockito.when(reader.read()).thenReturn((int)'1', -1);


    String actualResult = cls.funcToTest("");
    String expected = "1";
    assertEquals(expected, actualResult);
}

但是 reader.read() 方法不是 returning 1。相反,它总是 returns -1。我应该如何模拟 Reader 以便 read() 方法将 return 除了 -1.

之外的其他东西

谢谢。

一定有用,抱歉让你有点困惑)

// annotations is very important, cls I your tested class name, i assume cls is yours

@RunWith(PowerMockRunner.class)
@PrepareForTest({cls.class})
public class PrinterTest {

    @Test
    public void print() throws Exception {

        String url = "";
        GetMethod method = Mockito.mock(GetMethod.class);
        InputStream inputStream = Mockito.mock(InputStream.class);
        InputStreamReader reader = Mockito.mock(InputStreamReader.class);

        Mockito.when(method.getResponseBodyAsStream()).thenReturn(inputStream);
        //forgot about it )
        PowerMockito.whenNew(GetMethod.class).withArguments(eq(url)).thenReturn(method);
        PowerMockito.whenNew(InputStreamReader.class).withArguments(eq(inputStream)).thenReturn(reader);


        Mockito.when(reader.read()).thenReturn((int) '1', -1);
        when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);

        String actualResult = cls.funcToTest(url);
        String expected = "1";
        assertEquals(expected, actualResult);
    }


}

首先,您的测试代码进行了大量 .class 模拟以模拟函数局部变量/引用。模拟是针对 class 依赖项而不是函数局部变量。

正如所写,您无法单独使用模拟来测试您的函数 funcToTest。如果您不愿意将真实对象用于 - HttpMethod & Reader,则需要重写此函数。

如果您希望模拟对这些对象的调用并用此 get 方法替换 new 的代码,则需要删除此函数之外的带有 new 的对象创建代码。例如

protected HttpMethod getHttpMethod(String Url){
   return new GetMethod(url);
}

另外,我没有看到你嘲笑这一行是假的 URL - 这似乎是单元测试所必需的。

String url = Config.getURL(serviceName);

在你的函数之外获取对象创建代码后,你需要创建一个新的 class 而不是扩展你的 SUT(被测对象)并覆盖这些方法(getHttpMethod)提供 fake/mocked 个实例。

您需要编写类似的方法来获取 Reader 个实例。

然后测试这个新的 class - 从 SUT 扩展而来,因为对象创建逻辑不需要测试。

如果不将对象创建代码放在函数之外,我看不到通过 mockito 模拟它的方法。

希望对您有所帮助!!