JUnit/Mockito: как смоделировать или создать частную переменную-член

У меня есть частная строковая переменная filePath, которая будет установлена ​​в методе execute(..) SpringBoot, а затем значение будет использоваться в другом методе, который будет вызываться изнутри этого execute(..).

@Component("filebatchjobtask")
public class FileBatchJobTask extends BaseFileBatchJobTask implements Tasklet {


    private String filePath;   // PRIVATE VARIABLE THAT WILL BE USED IN A CALL 

    private static final CalLogger LOGGER = CalLoggerFactory.getLogger(FileBatchJobTask.class);

    @Override
    public RepeatStatus execute(final StepContribution stepContribution, final ChunkContext chunkContext) throws Exception {

        // INITIALIZE PRIVATE VARIABLE HERE
        filePath  = chunkContext.getStepContext().getJobParameters().get(Constants.FILEPATH).toString();
        
        processeFile();  // METHOD CALL WHERE FILEPATH INITIALIZED ABOVE WILL BE USED

        return RepeatStatus.FINISHED;
    }

    @Override
    protected void processeFile() throws IOException {
        LOGGER.warn("FileBatchJobTask:processeFile():: Directory to process files: " + filePath);
        File[] filelist = geteFiles(filePath);  // THIS IS THE CALL I WANT TO MOCK
        if (filelist == null || filelist.length < 1) {
            LOGGER.warn("FileBatchJobTask: No eFiles available to process");
            return;
        }

        LOGGER.warn("Total number of files to process: " + filelist.length);
}

Это соответствующий тест ниже:

//@RunWith(PowerMockRunner.class)
@RunWith(MockitoJUnitRunner.class)
public class FileBatchJobTaskTest extends BaseFileBatchJobTaskTest {

    @InjectMocks
    FileBatchJobTask fileBatchJobTask;

    @Override
    BaseFileBatchJobTask createFileBatchJobTask() {
        return fileBatchJobTask;
    }

    @Test
    public void processeFile() {
        BaseFileBatchJobTask batchJobTask = Mockito.spy(createFileBatchJobTask());
        
        // THIS resourceDir is the I want to use instead of filePath variable in tests here and pick file from this test resource path
        Path resourceDir = Paths.get("src", "test", "resources", "data", "validation");
        resourcePath = resourceDir.toFile().getAbsolutePath();

        File fileDir = new File(resourcePath);
        File[] files = fileDir.listFiles(new FileFilter() {
            @Override
            public boolean accept(final File pathname) {
                String name = pathname.getName().toLowerCase();
                return name.endsWith(".xml") && pathname.isFile();
            }
        });
        doReturn(files).when(batchJobTask).geteFiles(anyString());  // THIS IS THE CALL I AM TRYING TO MOCK
        

        try {
            
            fileBatchJobTask.processeFile();
            Assert.assertTrue(true);
        } catch (...) {

        }

}

Это базовый класс

class BaseFileBatchJobTask {

    protected File[] geteFiles(final String eFileDirPath) {
        File fileDir = new File(eFileDirPath);   // NPE as eFileDirPath is null
        File[] files = fileDir.listFiles(new FileFilter() {
            @Override
            public boolean accept(final File pathname) {
                String name = pathname.getName().toLowerCase();
                return name.endsWith(".xml") && pathname.isFile();
            }
        });

        return files;
    }

}

ERROR: Я получаю NPE, так как при запуске теста выполняется getEFiles(), а filePath имеет значение null. Поскольку я издеваюсь, это не должно входить в фактическую реализацию метода. Однако, похоже, над ним не издеваются, как ожидалось, поэтому нужна помощь в выяснении проблемы.

Также просмотрел много сообщений SO, но не смог понять проблему, поэтому, пожалуйста, не отмечайте как дубликат, если вы не знаете ответа :)


person Atihska    schedule 24.03.2021    source источник
comment
@Progman Я обновил fileBatchJobTask, чтобы он следил за комментарием Кэтрин ниже. Я не уверен, что я должен делать здесь, но просто пробую пробные способы. У вас есть представление о том, как это правильно сделать?   -  person Atihska    schedule 24.03.2021
comment
Поэтому я обновил и оставил шпиона только для batchJobTask, а не для fileBatchJobTask.   -  person Atihska    schedule 25.03.2021


Ответы (1)


Вам нужно вызвать processeFile() в шпионской версии вашего jobTask, а не в исходной. Подумайте о шпионе, являющемся оболочкой вокруг шпионского объекта, который перехватывает фиктивные вызовы.

Для краткости просто используйте batchJobTask внутри блока try-catch следующим образом:

    try {    
    
        batchJobTask.processeFile();
        Assert.assertTrue(true);
    } catch (...) {

    }
person Kathrin Geilmann    schedule 24.03.2021
comment
Я попробовал ваше предложение и означает ли это fileBatchJobTask = Mockito.spy(fileBatchJobTask);. Все та же ошибка. - person Atihska; 24.03.2021