简体   繁体   中英

PowerkMock-ing BufferedReader runs interminately

What I want to do is to mock newly created instance of BufferedReader . Here's the code that should be tested:

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 {
        ...
    }
}
...

What I have to do, is to PowerMock both FileReader creation and BufferedReader creation.

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"});
    }
}

But then the test never terminates. I can't even debug it.

As soon as PowerMockito.doAnswer() is removed the code is executed (and is available for debugging). I've also tried to use Mockito.mock() instead of PowerMockito.doAnswer() , it doesn't help.

What may cause interminate execution of the test?

Just a different perspective: one could say that your real problem in your code are those two calls to new() for FileReader / BufferedReader.

What if you passed a Reader to this method; instead of a String denoting a file name?

What if you passed a "ReaderFactory" to the underlying class that contains this method read(String) ? (where you would be using dependency injection to get that factory into your class)

Then: you would be looking at an improved design - and you would not need to use PowerMock. You could step back and go with Mockito or EasyMock; as there would be no more need to mock calls to new .

So, my answer is: you created hard-to-test code. Now you try to fix a design problem using the big (ugly) PowerMock hammer. Yes, that will work. But it is just the second best alternative.

The more reasonable option is to learn how to write testable code (start here for example); and well, write testable code. And stop using PowerMock ( I have done that many months back; after a lot of PowerMock-induced pain; and I have never ever regretted this decision ).

The problem was, that I also had to mock value after first bufferedReader.readLine() , because otherwise it would always return the mocked value, thus not terminating.

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

NOTE

Though this is the actual answer to the question, but you should strongly consider choosing the design GhostCat has suggested in another answer (which I eventually did).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM