I'm pretty new to mocking, and I've been trying to mock the actual contents (essentially create a virtual file in memory alone) so that no data is written to disk at any point.
I've tried solutions like mocking the file and mocking as many of the properties that I can figure out as much as possible, an then also writing into it with a filewriter/bufferedwriter, but those don't work well, since they need canonical paths. Anyone found a solution other than this or similar, but that I'm approaching this wrong?
I've been doing it like this:
private void mocking(){ File badHTML = mock(File.class); //setting the properties of badHTML when(badHTML.canExecute()).thenReturn(Boolean.FALSE); when(badHTML.canRead()).thenReturn(Boolean.TRUE); when(badHTML.canWrite()).thenReturn(Boolean.TRUE); when(badHTML.compareTo(badHTML)).thenReturn(Integer.SIZE); when(badHTML.delete()).thenReturn(Boolean.FALSE); when(badHTML.getFreeSpace()).thenReturn(0l); when(badHTML.getName()).thenReturn("bad.html"); when(badHTML.getParent()).thenReturn(null); when(badHTML.getPath()).thenReturn("bad.html"); when(badHTML.getParentFile()).thenReturn(null); when(badHTML.getTotalSpace()).thenReturn(0l); when(badHTML.isAbsolute()).thenReturn(Boolean.FALSE); when(badHTML.isDirectory()).thenReturn(Boolean.FALSE); when(badHTML.isFile()).thenReturn(Boolean.TRUE); when(badHTML.isHidden()).thenReturn(Boolean.FALSE); when(badHTML.lastModified()).thenReturn(System.currentTimeMillis()); when(badHTML.mkdir()).thenReturn(Boolean.FALSE); when(badHTML.mkdirs()).thenReturn(Boolean.FALSE); when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE); when(badHTML.setExecutable(true)).thenReturn(Boolean.FALSE); when(badHTML.setExecutable(false)).thenReturn(Boolean.TRUE); when(badHTML.setReadOnly()).thenReturn(Boolean.FALSE); try { BufferedWriter bw = new BufferedWriter(new FileWriter(badHTML)); /* badHTMLText is a string with the contents i want to put into the file, can be just about whatever you want */ bw.append(badHTMLText); bw.close(); } catch (IOException ex) { System.err.println(ex); } }
Any ideas or guidance would be very helpful. Somewhere after this i basically try to read from the file using another class. I would try to mock some sort of input stream, but the other class doesn't take an inputstream, since it's the io handling class for the project.
The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called. We don't need to do anything else to this method before we can use it.
They both achieve the same result. Using an annotation ( @Mock ) is usually considered "cleaner", as you don't fill up your code with boilerplate assignments that all look the same.
@InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock annotations into this instance. @Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class.
You seem to be after contradictory goals. On the one hand, you're trying to avoid writing data to disk, which isn't a bad goal in tests. On the other, you're trying to test your I/O-handling class, which means you'll be working with system utilities that assume that your File
will work with native calls. As such, here's my guidance:
File
. Just don't. Too many native things depend on it.File
and turns it into a Reader
, and the half that parses HTML out of the Reader
.StringReader
to simulate the data source.Don't be afraid to refactor your class to make testing easier, as here:
class YourClass { public int method(File file) { // do everything here, which is why it requires a mock } } class YourRefactoredClass { public int method(File file) { return methodForTest(file.getName(), file.isFile(), file.isAbsolute(), new FileReader(file)); } /** For testing only. */ int methodForTest( String name, boolean isFile, boolean isAbsolute, Reader fileContents) { // actually do the calculation here } } class YourTest { @Test public int methodShouldParseBadHtml() { YourRefactoredClass yrc = new YourRefactoredClass(); assertEquals(42, yrc.methodForTest( "bad.html", true, false, new StringReader(badHTMLText)); } }
At this point the logic in method
is so straightforward it's not worth testing, and the logic in methodForTest
is so easy to access that you can test it heavily.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With