Требуется, но не вызывается: Mockito PrintWriter

#java #mockito #junit4 #printwriter #powermockito

#java #mockito #junit4 #printwriter #powermockito

Вопрос:

Привет, я работаю над проектом и использую PrintWriter класс для открытия и записи в файл. Но когда я пишу тестовый пример для same, он выдает следующую ошибку в строке 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 внедрения с использованием компонентов. В чем ошибка, которую я делаю?? Я застрял на нем надолго и не получаю ошибку?
Любая помощь приветствуется.

Обновлено :

Я внес изменения, предложенные ниже, и обновил код, но теперь я получаю ошибку:

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

Комментарии:

1. постарайтесь не скрывать никаких исключений, оставив catch предложение пустым. Не могли бы вы включить печать или что-то еще там?

2. пожалуйста, обратите внимание, что @Mock отсутствует в lineIterator . Также вместо проверки print с новой строкой попробуйте проверить println без новой строки, это гораздо менее подвержено ошибкам, и скажите мне, помогает ли это

Ответ №1:

Я вижу 3 проблемы в вашем тесте:

  1. Вы не пытаетесь издеваться над правильным конструктором, на самом деле в методе execute вы создаете свой PrintWriter с только одним аргументом типа File , в то время как вы пытаетесь издеваться над конструктором с 2 аргументами, одним типа File , а другим типа String .

Таким образом, код скорее должен быть:

 PowerMockito.whenNew(PrintWriter.class)
    .withArguments(IMAGE_FILE)
    .thenReturn(mockPrintWriter);
  
  1. Чтобы иметь возможность имитировать конструктор, вам нужно подготовить класс, создающий экземпляр, который есть 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");
    }
}
  

Для получения более подробной информации, пожалуйста, обратитесь к Как имитировать построение новых объектов.


как я могу добавить проверку в модульный тест для writer.close?

Одним из способов может быть просто проверить, что close() вызывается один раз, добавив следующую строку в ваш модульный тест:

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

Комментарии:

1. Привет, спасибо. Это сработало. Но это показывает другую ошибку: требуется, но не вызывается: mockPrintWriter.print(«ASIN2 url1»); -> в softlines.ctl.ruleExecutor.tasks. ProcessImageDataTest.verify(ProcessImageDataTest.java:153) Однако были и другие взаимодействия с этим макетом: -> в softlines.ctl.ruleExecutor.tasks. ProcessImageData.execute(ProcessImageData.java:51) -> в softlines.ctl.ruleExecutor.tasks. ProcessImageData.execute(ProcessImageData.java:51) -> в softlines.ctl.ruleExecutor.tasks. ProcessImageData.execute(ProcessImageData.java:58)

2. Я обновил вопрос. можете ли вы сказать, почему не вызывается конкретное макет взаимодействия.

3. Готово!! Еще одна вещь. Где я могу закрыть средство записи в коде ProcessImageDataTest??

4. Или он будет закрыт автоматически, когда будет выполнена функция execute(), и когда, наконец, будет запущен блок, в строке 63 в коде?

5. да, вам не нужно использовать close() свой writer в вашем тесте, поскольку это уже сделано в методе execute()

Ответ №2:

Ваша конструкция 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
  

Итак, вам либо нужно изменить withArguments предложение PowerMockito, либо вам нужно добавить "UTF-8" к вызову конструктора в execute методе.