I'm trying to write unit tests for a method that takes a String filename, then opens the file and reads from it. So, to test that method, I thought about writing a file, then calling my method. However, in the build farm, it is not possible to write files arbitrarily to disk. Is there a standard way to "simulate" having a real file in my unit test?
-
What about using the temporary directory? see File#createTempFileMarc-Christian Schulze– Marc-Christian Schulze2012-08-07 16:01:57 +00:00Commented Aug 7, 2012 at 16:01
-
Is the file dynamic? Is the file name dynamic? What is expected from the stream?Woot4Moo– Woot4Moo2012-08-07 16:06:57 +00:00Commented Aug 7, 2012 at 16:06
-
createTempFile throws SecurityException, just my problem...Clovis– Clovis2012-08-07 16:11:16 +00:00Commented Aug 7, 2012 at 16:11
-
Just a configuration file for some object: I want to put together some configuration, and have the class read it, it's not very dynamic at all.Clovis– Clovis2012-08-07 16:11:53 +00:00Commented Aug 7, 2012 at 16:11
-
There's a related / duplicate question here: stackoverflow.com/questions/6840303/…Mark Butler– Mark Butler2014-03-06 18:30:30 +00:00Commented Mar 6, 2014 at 18:30
4 Answers
I've found that Mockito and Powermock are a good combination for this. Actually there's a blog post with a sample, where the File-class's constructor is mocked for testing purposes. Here's also a small example I threw together:
public class ClassToTest
{
public void openFile(String fileName)
{
File f = new File(fileName);
if(!f.exists())
{
throw new RuntimeException("File not found!");
}
}
}
Testing with Mockito + Powermock:
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassToTest.class)
public class FileTest
{
@Test
public void testFile() throws Exception
{
//Set up a mocked File-object
File mockedFile = Mockito.mock(File.class);
Mockito.when(mockedFile.exists()).thenReturn(true);
//Trap constructor calls to return the mocked File-object
PowerMockito.whenNew(File.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(mockedFile);
//Do the test
ClassToTest classToTest = new ClassToTest();
classToTest.openFile("testfile.txt");
//Verify that the File was created and the exists-method of the mock was called
PowerMockito.verifyNew(File.class).withArguments("testfile.txt");
Mockito.verify(mockedFile).exists();
}
}
1 Comment
If you use JUnit, there is the TemporaryFolder. Files are deleted after the test. Example given on the page:
public static class HasTempFolder {
@Rule
public TemporaryFolder folder= new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File createdFile= folder.newFile("myfile.txt");
File createdFolder= folder.newFolder("subfolder");
// ...
}
}
However, I have also used it for testing my Android class read/write capabilities like:
[...]
pw = new PrintWriter(folder.getAbsolutePath() + '/' + filename);
pw.println(data);
2 Comments
How about using mocked stream classes, which override the real ones (like BufferredReader, File) completely (meaning all methods or all methods you use)? The data can be saved as an array of bytes, for example, in some singleton, if they are to be used between different test classes.
1 Comment
This is highly frowned upon:
The smallest amount of testable code. Often a single method/function, sans the use of other methods or classes. Fast! Thousands of unit tests can run in ten seconds or less! A unit test NEVER uses:
- a database
- an app server (or server of any kind)
- file/network I/O or file system;
- another application;
- the console (System.out, System.err, etc.)
- logging
- most other classes (exceptions include DTO's, String, Integer, mocks and maybe a few others). "
If you must read from a file, have a test file pre-generated that all unit tests read from. There is no need to write anything to disk.