Java PowerkMock ing BufferedReader间歇运行

Java PowerkMock ing BufferedReader间歇运行,java,unit-testing,mocking,powermock,test-double,Java,Unit Testing,Mocking,Powermock,Test Double,我想做的是模拟新创建的BufferedReader实例。下面是应该测试的代码: A.java ... @Override public String read(String fileName) throws IOException { ... try { fileReader = new FileReader(fileName); bufferedReader = new BufferedReader(fileReader); S

我想做的是模拟新创建的
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 {
        ...
    }
}
...
@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"});
    }
}
我要做的是,对
FileReader
创建和
BufferedReader
创建进行PowerMock

ATest.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 {
        ...
    }
}
...
@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()之后模拟值,因为否则它将始终返回模拟值,因此不会终止

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


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

< P>问题是,在第一个代码> BuffReDeReald.RealLoad()/代码>之后,我还必须模拟值,因为否则它总是返回被嘲弄的值,因此不会终止。

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


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

< P>只是一个不同的观点:可以说,你的<强>真正的< /强>问题是对FieleRADE/BuffReDeRe读器的两个调用:<代码>新()/代码>。p> 如果您向该方法传递了一个读取器,该怎么办;而不是表示文件名的字符串

如果您将“ReaderFactory”传递给包含此方法的基础类
read(String)
,该怎么办?(您将使用依赖项注入将工厂引入类中)

然后:您将看到一个改进的设计,而您不需要使用PowerMock。你可以退后一步,和莫基托或易莫克一起去;因为不再需要模拟调用
new

所以,我的答案是:您创建了难以测试的代码。现在,您尝试使用大型(丑陋的)PowerMock hammer修复一个设计问题。是的,那会有用的。但这只是第二个最好的选择


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

只是从另一个角度来看:可以说代码中真正的问题是对FileReader/BufferedReader的
new()
的两个调用

如果您向该方法传递了一个读取器,该怎么办;而不是表示文件名的字符串

如果您将“ReaderFactory”传递给包含此方法的基础类
read(String)
,该怎么办?(您将使用依赖项注入将工厂引入类中)

然后:您将看到一个改进的设计,而您不需要使用PowerMock。你可以退后一步,和莫基托或易莫克一起去;因为不再需要模拟调用
new

所以,我的答案是:您创建了难以测试的代码。现在,您尝试使用大型(丑陋的)PowerMock hammer修复一个设计问题。是的,那会有用的。但这只是第二个最好的选择


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

谢谢,这很有道理。非常欢迎您。当人们回答这样的问题时,我总是很高兴,“但我必须测试的不是我的代码;所以PowerMock是我唯一的选择”——)正如旁注:这里有FileUtilities.readAllLines()-接受一个字符串,并返回该文件中所有行的列表(您可以很容易地找到一个字符串)。因此,也许不必第无数次重新实现“完全读入字符串”,您也可以使用现有无数实现中的一个。我相信ApacheCommons、guava都有这样的方法!谢谢,很有道理。非常欢迎你。当人们回答这样的问题时,我总是很高兴,“但我必须测试的不是我的代码;所以PowerMock是我唯一的选择”——)正如旁注:这里有FileUtilities.readAllLines()-接受一个字符串,并返回该文件中所有行的列表(您可以很容易地找到一个字符串)。因此,也许不必第无数次重新实现“完全读入字符串”,您也可以使用现有无数实现中的一个。我相信ApacheCommons、guava都有这样的方法!