3

I am new to jMockit. I am trying to mock multiple instances of java.io.File type in a method. There are some places where, I shouldn't mock file Object. For that reason, I am using @Injectable. It is throwing the below exception.

I don't want to mock all the instances of java.io.File.I want the instances returned from the methods to be actual Files.

The below is test class.

/**
 * 
 */
package org.iis.uafdataloader.tasklet;

import static org.junit.Assert.fail;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.regex.Pattern;

import mockit.Expectations;
import mockit.Injectable;
import mockit.Mocked;
import mockit.NonStrictExpectations;
import mockit.VerificationsInOrder;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.RegexFileFilter;
import org.iis.uafdataloader.tasklet.validation.FileNotFoundException;
import org.junit.Test;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.repeat.RepeatStatus;

/**
 * @author K23883
 *
 */
public class FileMovingTaskletTest {

    private FileMovingTasklet fileMovingTasklet;

    @Mocked
    private StepContribution contribution;

    @Mocked
    private ChunkContext chunkContext;



    /**
     * Test method for
     * {@link org.iis.uafdataloader.tasklet.FileMovingTasklet#execute(org.springframework.batch.core.StepContribution, org.springframework.batch.core.scope.context.ChunkContext)}
     * .
     * 
     * @throws Exception
     */
    @Test
    public void testExecuteWhenWorkingDirDoesNotExist(
//          @Mocked final File file,
            @Injectable final File sourceDirectory,
            @Injectable final File workingDirectory,
            @Injectable final File archiveDirectory,
            @Mocked final RegexFileFilter regexFileFilter,
            @Mocked final FileUtils fileUtils) throws Exception {

        fileMovingTasklet = new FileMovingTasklet();
        fileMovingTasklet.setSourceDirectoryPath("sourceDirectoryPath");
        fileMovingTasklet.setInFileRegexPattern("inFileRegexPattern");
        fileMovingTasklet.setArchiveDirectoryPath("archiveDirectoryPath");
        fileMovingTasklet.setWorkingDirectoryPath("workingDirectoryPath");



        final File[] sourceDirectoryFiles = new File[] {
                new File("sourceDirectoryPath/ISGUAFFILE.D140728.C00"),
                new File("sourceDirectoryPath/ISGUAFFILE.D140729.C00") };

        final File[] workingDirectoryFiles = new File[] {
                new File("workingDirectoryPath/ISGUAFFILE.D140728.C00"),
                new File("workingDirectoryPath/ISGUAFFILE.D140729.C00") };




        new NonStrictExpectations(){{

                new File("sourceDirectoryPath");
                result = sourceDirectory;

                sourceDirectory.exists();
                result = true;

                sourceDirectory.isDirectory();
                result = true;

                // workingDirectory =
                new File("workingDirectoryPath");
                result = workingDirectory;

                workingDirectory.exists();
                result = false;

                workingDirectory.mkdirs();

                FileUtils.cleanDirectory(onInstance(workingDirectory));

                FilenameFilter fileNameFilter = new RegexFileFilter(anyString,
                        Pattern.CASE_INSENSITIVE);

                sourceDirectory.listFiles(fileNameFilter);
                result = sourceDirectoryFiles;

                System.out.println("sourceDirectoryFile :"
                        + ((File[]) sourceDirectoryFiles).length);

                // for (int i = 0; i < sourceDirectoryFiles.length; i++) {
                // FileUtils.moveFileToDirectory(sourceDirectoryFiles[i],
                // workingDirectory, true);
                // }

                // archiveDirectory =
                new File("archiveDirectoryPath");
                result = archiveDirectory;

                workingDirectory.listFiles();
                result = workingDirectoryFiles;

                // for (int i = 0; i < workingDirectoryFiles.length; i++) {
                // FileUtils.copyFileToDirectory(workingDirectoryFiles[i],
                // archiveDirectory);
                // }

            }};


            RepeatStatus status = fileMovingTasklet.execute(contribution,
                    chunkContext);
            assert (status == RepeatStatus.FINISHED);


        new VerificationsInOrder() {{

            sourceDirectory.exists();
            onInstance(sourceDirectory).isDirectory();
            onInstance(workingDirectory).exists();

            onInstance(workingDirectory).mkdirs();

            onInstance(sourceDirectory).listFiles((FilenameFilter)any);

            FileUtils.moveFileToDirectory((File)any, onInstance(workingDirectory), true); 
            times = 2;

            FileUtils.copyFileToDirectory((File)any, onInstance(archiveDirectory));
            times= 2;

        }};

    }

}

The below is actual implementation method

/*
 * (non-Javadoc)
 * 
 * @see org.springframework.batch.core.step.tasklet.Tasklet#execute(org.
 * springframework.batch.core.StepContribution,
 * org.springframework.batch.core.scope.context.ChunkContext)
 */
@Override
public RepeatStatus execute(StepContribution contribution,
        ChunkContext chunkContext) throws Exception {

    File sourceDirectory = new File(sourceDirectoryPath);

    if (sourceDirectory == null || !sourceDirectory.exists()
            || !sourceDirectory.isDirectory()) {
        throw new FileNotFoundException("The source directory '"
                + sourceDirectoryPath
                + "' doesn't exist or can't be read or not a directory");
    }


    File workingDirectory = new File(workingDirectoryPath);

    if (workingDirectory != null && !workingDirectory.exists() ) {
        workingDirectory.mkdirs();

    }

    FileUtils.cleanDirectory(workingDirectory);

    FilenameFilter fileFilter = new RegexFileFilter(inFileRegexPattern,
            Pattern.CASE_INSENSITIVE);

    File[] sourceDirectoryFiles = sourceDirectory.listFiles(fileFilter);

    System.out.println("sourceDirectoryFiles : " + sourceDirectoryFiles.length);

    for (File file : sourceDirectoryFiles) {
        FileUtils.moveFileToDirectory(file, workingDirectory, true);
    }

    File archiveDirectory =  new File(archiveDirectoryPath);

    for (File file : workingDirectory.listFiles()) {
        FileUtils.copyFileToDirectory(file, archiveDirectory);
    }

    return RepeatStatus.FINISHED;
}

The below is stack trace.

java.lang.IllegalStateException: Missing invocation to mocked type at this point; please make sure such invocations appear only after the declaration of a suitable mock field or parameter
    at org.iis.uafdataloader.tasklet.FileMovingTaskletTest$1.<init>(FileMovingTaskletTest.java:75)
    at org.iis.uafdataloader.tasklet.FileMovingTaskletTest.testExecuteWhenWorkingDirDoesNotExist(FileMovingTaskletTest.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Please, help me in solving the problem.

krishth
  • 83
  • 1
  • 1
  • 9

1 Answers1

2

@Injectable gives you a single mocked instance; it won't affect other instances of the mocked type. So, when the test attempts to record new File("sourceDirectoryPath"), it says "missing invocation to mocked type at this point" precisely because the File(String) is not mocked.

To mock the entire File class (including its constructors) so that all instances are affected, you need to use @Mocked instead, as the following example shows:

@Test
public void mockFutureFileObjects(@Mocked File anyFile) throws Exception
{
    final String srcDirPath = "sourceDir";
    final String wrkDirPath = "workingDir";

    new NonStrictExpectations() {{
        File srcDir = new File(srcDirPath);
        srcDir.exists(); result = true;
        srcDir.isDirectory(); result = true;

        File wrkDir = new File(wrkDirPath);
        wrkDir.exists(); result = true;
    }};

    sut.execute(srcDirPath, wrkDirPath);
}

The JMockit Tutorial describes the same mechanism, although with a slightly different syntax.

This said, I would suggest instead to write the test with real files and directories.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • Thanks for answering. But, I don't want to mock all the instances of "File". I want to mock only the given 3 instances. – krishth Aug 01 '14 at 15:36
  • Ah, yes; in that case, use partial mocking: `new NonStrictExpectations(File.class)`, while removing the `@Mocked File` parameter. – Rogério Aug 01 '14 at 20:38
  • Could you please, provide some reference how to implement it. Thank you very much. – krishth Aug 01 '14 at 20:41
  • The URLs listed in this answer are **all leading to a different site**...:( very very different--and should be changed. The [following URL to github](http://jmockit.github.io/tutorial/Mocking.html) is now the valid URL for the JMockit Tutorial. – Jordan Gee Apr 18 '19 at 00:22