Reputation: 4461
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?
Upvotes: 9
Views: 27041
Reputation: 1566
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);
Upvotes: 3
Reputation: 24316
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.
Upvotes: -2
Reputation: 16035
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();
}
}
Upvotes: 19
Reputation: 1888
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.
Upvotes: 0