YourAboutMeIsBlank
YourAboutMeIsBlank

Reputation: 1907

How to unit test and mock a method that takes a file as a parameter

I have a class CollectionObject which creates a ArrayList.

public class CollectionObject {

    private List<String> collectionObject;

    public CollectionObject() {
        collectionObject = new ArrayList<String>();
    }

    public List<String> getCollectionObject() {
        return collectionObject;
    }

    public void add(final String stringToWrite) throws VerifyException {
        collectionObject.add(stringToWrite);
    }
}

There is another class which takes in the class CollectionObject and uses it to write the contents of the file to the class CollectionObject.

public class ReaderFileWriterObjectService {

    private BufferedReader bufferedReader;
    private CollectionObject collectionObject;
    private String line;

    public CollectionObject getCollectionObjectAfterWritingFromAFile(final File file)
            throws VerifyException, IOException {
        collectionObject = new CollectionObject();
        bufferedReader = new BufferedReader(new FileReader(file));
        while ((line = bufferedReader.readLine()) != null) {
            collectionObject.add(line);
        }
        bufferedReader.close();
        return collectionObject;
    }

How to Test and Mock the method of the class ReaderFileWriterObjectService?

Upvotes: 3

Views: 11861

Answers (6)

Guna
Guna

Reputation: 316

I am doing the same thing, And the following idea is working, I hope this will work for u too,

 @InjectMocks
 private CollectionObject collectionObject;

@Test
public void getCollectionObjectAfterWritingFromAFile() throws Exception {
    CollectionObject  expectedObject =new CollectionObject();
    List<String> expectedList=new ArrayList<String>();
    expectedList.add("100");

    CollectionObject  resultObject =new CollectionObject();

    BufferedReader reader=new BufferedReader(new StringReader("100"));
    PowerMockito.mock(BufferedReader.class);
    PowerMockito.mock(FileReader.class);
    PowerMockito.whenNew(FileReader.class).withArguments("test10.csv").thenReturn(null);
    PowerMockito.whenNew(BufferedReader.class).withArguments(null).thenReturn(reader);
    resultObject=collectionObject.getCollectionObjectAfterWritingFromAFile( "test10.csv");
    assertEquals(expectedObject ,resultObject );
}

Upvotes: 2

fge
fge

Reputation: 121710

Let me complement on @LouisWasserman's answer.

You just cannot test APIs which rely on java.io.File; this class cannot be reliably unit tested (even though it is not even final at the JDK level).

But this is not the case with the new filesystem API, which appeared with Java 7.

Also known as JSR 203, this API provides a unified API to any storage medium providing "filesystem objects".

Short story:

  • a "filesystem object" is materialized by a Path in this API;
  • any JDK implementing JSR 203 (ie, any Java 7+ version) supports this API;
  • to get a Path from a resource on the default FileSystem, you can use Paths.get();
  • but you are not limited to that.

In short, in your API and test case, you should use Path, not File. And if you want to test anything related to some filesystem resource, use the JDK's Files class to test Path instances.

And you can create FileSystems out of your main, disk based, file system. Recommendation: use this.

Upvotes: 4

Stefan Birkner
Stefan Birkner

Reputation: 24520

You can use JUnit's TemporaryFolder for creating a file and copy the contents from a resource to it.

public YourText {
  @Rule
  public TemporaryFolder folder = new TemporaryFolder();

  @Test
  public void checkSomething() throws Exception {
    InputStream resource = getClass().getResourceAsStream("/your/resource");
    File file = folder.newFile();
    Files.copy(resource, file);
    ReaderFileWriterObjectService service = ...
    CollectionObject collection = service
        .getCollectionObjectAfterWritingFromAFile(file);
    ...
  }

Upvotes: 1

user3458
user3458

Reputation:

I'd suggest changing the API to accept Reader or BufferedReader - those can be mocked. Hide the dependency on file with a factory.

Upvotes: 0

D. Rakov
D. Rakov

Reputation: 338

Okay, at first lets consider what do u want to test? If it is unit test then u dont want to test integrations like communications with filesystem, you have to test your own logic and your logic is something like: 1) Read next line from file using file system integration 2) add this line into my object

The second step you should not test because this method is too easy to break. The first step you can't test cause it performs integrations call. So i don't think that here u need a unit test

But if your logic will be more complicated, then you can introduce interface wrapper and mock it in your test:

public interface FileWrapper{
  public String readLine();
  public void close();
}
public class FileWrapperImpl implements FileWrapper{
  private File file;
  private BufferedReader reader;

  public FileWrapperImpl (File file){
     this.file = file;
     this.reader= ...
  }

  public String readLine(){
    return reader.nextLine();
  }
}

And then your ReaderFileWriterObjectService:

 public CollectionObject getCollectionObjectAfterWritingFromAFile(FileWrapper wrapper)
        CollectionObject  collectionObject = new CollectionObject();
        while ((line = wrapper.readLine()) != null) {
            collectionObject.add(line);
        }
        wrapper.close();
        return collectionObject;
    }

And now you can easily mock FileWrapper for test and pass it to your service

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198093

You cannot. You're pretty much out of luck. A better design would accept a Java 7 java.nio.file.FileSystem and a Path that could be swapped out for a test implementation, e.g. https://github.com/google/jimfs.

Upvotes: 0

Related Questions