想要但不调用:Mockito PrintWriter

Wanted but not invoke: Mockito PrintWriter

您好,我正在做一个项目并使用 PrintWriter class 打开和写入文件。但是当我为它编写测试用例时,它在第 153 行

处给出了以下错误
Wanted but not invoked:
  mockPrintWriter.println("ID    url1
  ");
 -> at x.y.z.verify(ProcessImageDataTest.java:153)
 Actually, there were zero interactions with this mock.

代码:(使用 Lombok 库)

ProcessImageData.java

@Setter
@RequiredArgsConstructor
public class ProcessImageData implements T {
    private final File newImageDataTextFile;

   @Override
    public void execute() {
       LineIterator inputFileIterator = null;
       try {
        File filteredImageDataTextFile = new File(filteredImageDataTextFilepath);

          PrintWriter writer = new PrintWriter(newImageDataTextFile);
          inputFileIterator = FileUtils.lineIterator(filteredImageDataTextFile, StandardCharsets.UTF_8.displayName());
          while (inputFileIterator.hasNext()) {
                    if(someCondition)
           **Line51**           writer.println(imageDataFileLine);
                    //FileUtils.writeStringToFile(newImageDataTextFile, imageDataFileLine + NEWLINE, true);
                }
            }          

      } catch (Exception e) {

      } finally {
          LineIterator.closeQuietly(inputFileIterator);
 **LINE63**         writer.close();
      }
  }

ProcessImageDataTest.java

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

private ProcessImageData processImageData;

private static final String FILTERED_IMAGE_DATA_TEXT_FILE_PATH = "filteredFilepath";
private File FILTEREDFILE = new File(FILTERED_PATH);
private static final File IMAGE__FILE = new File("imageFilePath");

private LineIterator lineIterator;
@Mock
private PrintWriter mockPrintWriter;

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

    processImageData = new ProcessImageData(Palettes_file, FILTERED_PATH, IMAGE_FILE);

    PowerMockito.mockStatic(FileUtils.class);
    PowerMockito.whenNew(PrintWriter.class).withArguments(IMAGE_FILE).thenReturn(mockPrintWriter);

    PowerMockito.when(FileUtils.lineIterator(FILTERED_FILE, StandardCharsets.UTF_8.displayName())).thenReturn(lineIterator);
    PowerMockito.when(lineIterator.hasNext()).thenReturn(true, true, false);

}

@Test
public void testTaskWhenIDInDBAndStale() throws IOException {
    PowerMockito.when(lineIterator.nextLine()).thenReturn(ID2 + SPACE + URL1, ID1 + SPACE + URL2);

    processImageData.execute();

    List<String> exepctedFileContentOutput = Arrays.asList(ID2 + SPACE + URL1 + NEWLINE);
    verify(exepctedFileContentOutput, 1, 1);
}


@Test
public void testTaskWhenIDNotInDB() throws IOException {
    PowerMockito.when(lineIterator.nextLine()).thenReturn(ID2 + SPACE + URL1, ID3 + SPACE + URL2);

    processImageData.execute();

    List<String> exepctedFileContentOutput = Arrays.asList(ID3 + SPACE + URL2 + NEWLINE);
    verify(exepctedFileContentOutput, 1, 1);
}

private void verify(List<String> exepctedFileContentOutput, int fileWriteTimes, int fileReadTimes) throws IOException {
    for (String line : exepctedFileContentOutput){
**Line153**                     Mockito.verify(mockPrintWriter,  Mockito.times(fileWriteTimes)).print(line);  
    }

    PowerMockito.verifyStatic(Mockito.times(fileReadTimes));
    FileUtils.lineIterator(FILTERED_IMAGE_DATA_TEXT_FILE, StandardCharsets.UTF_8.displayName());
}

}

我也在模拟 PrintWriter 的新运算符,使用 bean 注入。我做错了什么??我坚持了很长时间而没有收到错误消息? 感谢任何帮助。

已更新 :

我做了下面建议的更改并更新了代码,但现在我收到错误:

Wanted but not invoked: mockPrintWriter.print("ASIN2 url1 "); -> 
at softlines.ctl.ruleExecutor.tasks.ProcessImageDataTest.verify‌​(ProcessImageDataTes‌​t.java:153) 
However, there were other interactions with this mock: -> at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​51) ->  
at  softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​51) -> 
at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​58) –

您的 PrintWriter 构造与模拟不匹配。你告诉 PowerMockito return 你的模拟是这样的:

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

所以你不得不说:

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

但是在您正在测试的代码中的 execute 方法中,您这样做:

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

因此您要么需要更改 PowerMockito withArguments 子句,要么需要将 "UTF-8" 添加到 execute 方法中的构造函数调用。

我在你的测试中发现了 3 个问题:

  1. 您不会尝试模拟 正确的构造函数 ,实际上在方法 execute 中,您使用 创建了 PrintWriter只有一个 File 类型的参数 当您尝试模拟 具有 2 个参数 类型 File 和另一个 File 类型的构造函数时=18=].

所以代码应该是:

PowerMockito.whenNew(PrintWriter.class)
    .withArguments(IMAGE_FILE)
    .thenReturn(mockPrintWriter);
  1. 为了能够模拟构造函数,您需要准备 class 创建实例,在本例中为 ProcessImageData,因此您需要添加 ProcessImageData.class 在注解中 @PrepareForTest。 (我不确定那里是否需要 ProcessImageDataTest.class

  2. 字段lineIterator应该用@Mock注释。

  3. 不用换行验证print,应该直接验证println 不用换行这样错误会少很多俯卧


我简化了你的代码来展示这个想法。

假设ProcessImageData是:

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

我的单元测试将是:

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

详情请参考How to mock construction of new objects


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

一种方法是通过将下一行添加到单元测试来简单地检查 close() 是否被调用一次:

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