1

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?

azizbekian
  • 60,783
  • 13
  • 169
  • 249

2 Answers2

3

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 ).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Thanks, makes perfect sense. – azizbekian Feb 12 '17 at 18:49
  • 1
    You are very welcome. I am always glad when people dont come back on such answers with "but it is not my code i have to test; so PowerMock is the only choice for me" ;-) – GhostCat Feb 12 '17 at 19:08
  • 1
    And just as side note: there is FileUtilities.readAllLines() - takes a string, and returns a list of all the lines in that file (which you could easily concat to get a single string). So maybe instead of re-implementing a "full read into string" for the zillionth time, you could also just use one of the zillion existing implementations. I am sure apache commons, guava, they all have methods for that! – GhostCat Feb 12 '17 at 19:10
1

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).

Community
  • 1
  • 1
azizbekian
  • 60,783
  • 13
  • 169
  • 249