Wanted but not invoke: Mockito PrintWriter

戏子无情 提交于 2019-12-02 03:34:16

I see 3 issues in your test:

  1. You don't try to mock the correct constructor, indeed in the method execute, you create your PrintWriter with only one argument of type File while you try to mock the constructor with 2 arguments one of type File and the other one of type String.

So the code should rather be:

PowerMockito.whenNew(PrintWriter.class)
    .withArguments(IMAGE_FILE)
    .thenReturn(mockPrintWriter);
  1. To be able to mock a constructor you need to prepare the class creating the instance which is ProcessImageData in this case, so you need to add ProcessImageData.class in the annotation @PrepareForTest. (I'm not sure ProcessImageDataTest.class is needed there)

  2. The field lineIterator should be annotated with @Mock.

  3. Instead of verifying print with a new line, you should verify directly println without new line it is much less error prone.


I simplified your code to show the idea.

Assuming that ProcessImageData is:

public class ProcessImageData {

    private final File newImageDataTextFile;

    public ProcessImageData(final File newImageDataTextFile) {
        this.newImageDataTextFile = newImageDataTextFile;
    }

    public void execute() throws Exception{
        try (PrintWriter writer = new PrintWriter(newImageDataTextFile)) {
            LineIterator inputFileIterator = FileUtils.lineIterator(
                newImageDataTextFile, StandardCharsets.UTF_8.displayName()
             );
            while (inputFileIterator.hasNext()) {
                writer.println(inputFileIterator.nextLine());
            }
        }
    }
}

My unit test would then be:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ProcessImageData.class, FileUtils.class})
public class ProcessImageDataTest {

    private File file = new File("imageFilePath");

    private ProcessImageData processImageData;
    @Mock
    private PrintWriter mockPrintWriter;
    @Mock
    private LineIterator lineIterator;

    @Before
    public void init() throws Exception {
        MockitoAnnotations.initMocks(this);

        processImageData = new ProcessImageData(file);
        PowerMockito.whenNew(PrintWriter.class)
            .withArguments(file)
            .thenReturn(mockPrintWriter);
        PowerMockito.mockStatic(FileUtils.class);
        PowerMockito.when(
            FileUtils.lineIterator(file, StandardCharsets.UTF_8.displayName())
        ).thenReturn(lineIterator);
        PowerMockito.when(lineIterator.hasNext()).thenReturn(true, true, false);
    }

    @Test
    public void testExecute() throws Exception {
        PowerMockito.when(lineIterator.nextLine()).thenReturn("Foo", "Bar");
        processImageData.execute();
        Mockito.verify(mockPrintWriter,  Mockito.times(1)).println("Foo");
        Mockito.verify(mockPrintWriter,  Mockito.times(1)).println("Bar");
    }
}

For more details please refer to How to mock construction of new objects.


how can I add verification in unit test for writer.close?

One way could be to simply check that close() at be called once by adding the next line to your unit test:

Mockito.verify(mockPrintWriter,  Mockito.times(1)).close();

Your construction of the PrintWriter doesn't match the mock. You told PowerMockito to return your mock like this:

PowerMockito.whenNew(PrintWriter.class).withArguments(IMAGE_FILE , StandardCharsets.UTF_8.name()).thenReturn(mockPrintWriter);

So you would have to say:

new PrintWriter(IMAGE_FILE, "UTF-8"); // 2 arguments

But instead in your execute method in the code that is being tested, you do:

PrintWriter writer = new PrintWriter(newImageDataTextFile); // only 1 argument

So you either need to change the PowerMockito withArguments clause, or you need to add "UTF-8" to the constructor invocation in the execute method.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!