想要但不要援引:Mockito PrintWriter

嗨,我正在研究一个项目,并使用PrintWriter类在文件中打开和写入。 但是当我为相同的情况编写测试用例时,它会在第153行给出以下错误

 Wanted but not invoked: mockPrintWriter.println("ID url1 "); -> at xyzverify(ProcessImageDataTest.java:153) Actually, there were zero interactions with this mock. 

代码:(使用龙目岛图书馆)

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 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 exepctedFileContentOutput = Arrays.asList(ID3 + SPACE + URL2 + NEWLINE); verify(exepctedFileContentOutput, 1, 1); } private void verify(List 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) – 

我在你的测试中看到3个问题:

  1. 你不试图模拟正确的构造函数 ,实际上在方法execute ,你创建的PrintWriter 只有一个 File类型的参数 ,而你试图用2个参数模拟构造函数 ,类型为File ,另一个类型为String

所以代码应该是:

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

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

  3. 您应该在没有新行的情况下直接validationprintln ,而不是使用新行validationprint ,而不是更容易出错。


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

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

我的unit testing将是:

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

有关更多详细信息,请参阅如何模拟新对象的构造


如何在writer.close的unit testing中添加validation?

一种方法是通过在unit testing中添加下一行来简单地检查close()被调用一次:

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

您的PrintWriter构造与模拟不匹配。 你告诉PowerMockito像这样返回你的模拟:

 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子句,或者需要在execute方法中向构造函数调用添加"UTF-8"