PowerkMock-ing BufferedReader 间歇运行

PowerkMock-ing BufferedReader runs interminately

我想做的是模拟新创建的 BufferedReader 实例。这是应该测试的代码:

A.java

...
@Override
public String read(String fileName) throws IOException {
    ...

    try {
        fileReader = new FileReader(fileName);
        bufferedReader = new BufferedReader(fileReader);
        String tmp;
        StringBuilder builder = new StringBuilder();
        while ((tmp = bufferedReader.readLine()) != null) {
            builder.append(tmp);
        }
        return builder.toString();
    } catch (IOException e) {
        ...
    } finally {
        ...
    }
}
...

我必须做的是 PowerMock FileReader 创建和 BufferedReader 创建。

ATest.java

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class ATest {

    @Mock
    private FileReader fileReader;
    @Mock
    private BufferedReader bufferedReader;
    ...

    @Test
    public void test() throws Exception {
        PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader);
        PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader);
        PowerMockito.doAnswer(new Answer() {
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return "test";
            }
        }).when(bufferedReader).readLine();
        assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"});
    }
}

但是测试永远不会终止。我什至不能调试它。

一旦 PowerMockito.doAnswer() 被删除,代码就会被执行(并且可用于调试)。我也尝试过使用 Mockito.mock() 而不是 PowerMockito.doAnswer(),但没有用。

什么可能导致测试终止执行?

问题是,我还必须在第一个 bufferedReader.readLine() 之后模拟值,否则它总是 return 模拟值,因此不会终止。

    Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null);

注意

虽然这是问题的实际答案,但您应该强烈考虑在另一个答案(我最终选择了)中选择设计

只是换个角度:可以说代码中的 真正的 问题是对 new() for FileReader / Buffered[ 的两次调用=43=]。

如果您将 Reader 传递给此方法会怎么样?而不是表示文件名的字符串?

如果将 "ReaderFactory" 传递给包含此方法 read(String) 的底层 class 会怎样? (您将使用 依赖注入 将该工厂放入您的 class)

然后:您将查看 改进的 设计 - 您 不需要 需要使用 PowerMock。您可以退后一步,使用 Mockito 或 EasyMock;因为不再需要模拟调用 new.

所以,我的回答是:您创建了 hard-to-test 代码。现在您尝试使用大(丑陋)的 PowerMock 锤子修复设计问题。是的,那会起作用。但它只是第二好的选择。

更合理的选择是学习如何编写可测试的代码(例如开始here);好吧,编写可测试的代码。并停止使用 PowerMock(我几个月前就这样做了;在经历了很多 PowerMock-induced 痛苦之后;我 从来没有 后悔这个决定)。