#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(ProcessImageDataTest.java:153)
However, there were other interactions with this mock: -> at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(ProcessImageData.java:51) ->
at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(ProcessImageData.java:51) ->
at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(ProcessImageData.java:58) –
Комментарии:
1. постарайтесь не скрывать никаких исключений, оставив
catch
предложение пустым. Не могли бы вы включить печать или что-то еще там?2. пожалуйста, обратите внимание, что
@Mock
отсутствует вlineIterator
. Также вместо проверкиprintln
без новой строки, это гораздо менее подвержено ошибкам, и скажите мне, помогает ли это
Ответ №1:
Я вижу 3 проблемы в вашем тесте:
- Вы не пытаетесь издеваться над правильным конструктором, на самом деле в методе
execute
вы создаете свойPrintWriter
с только одним аргументом типаFile
, в то время как вы пытаетесь издеваться над конструктором с 2 аргументами, одним типаFile
, а другим типаString
.
Таким образом, код скорее должен быть:
PowerMockito.whenNew(PrintWriter.class)
.withArguments(IMAGE_FILE)
.thenReturn(mockPrintWriter);
-
Чтобы иметь возможность имитировать конструктор, вам нужно подготовить класс, создающий экземпляр, который есть
ProcessImageData
в данном случае, поэтому вам нужно добавитьProcessImageData.class
в аннотацию@PrepareForTest
. (Я не уверен, чтоProcessImageDataTest.class
там нужно) -
Поле
lineIterator
должно быть помечено@Mock
. -
Вместо проверки
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
методе.