views:

280

answers:

4

Hello,

I have recently been introduced to EasyMock and have been asked to develop some unit tests for a FileMonitor class using it. The FileMonitor class is based on a timed event that wakes up and checks for file modification(s) in a defined list of files and directories. I get how to do this using the actual file system, write a test that writes to a file and let the FileMonitor do its thing. So, how do I do this using EasyMock? I just don't get how to have EasyMock mock the file system.

Thanks, Todd

A: 

The basic technique for mocking is to introduce an interface (if the current design doesn't have one) that provides methods for the real service (the dependency) that is being mocked. The test is testing that the class under test interacts correctly with the dependency. Correctly here means that it does what you expect it to do. That does not mean it does the right thing, as the right thing can only be determined by an integration test that uses the real components (what you envision doing by creating a real file).

So you need to have a method on the class under test that lets you pass in an implementation of this interface. The most obvious is via the constructor. You have the production constructor which initializes the class with the real implementation of the interface that hits the real file system, and then under test you pass in the mock to the constructor.

In the test you run the methods on the class and assert that the interface was called in the way you expect.

I will note that coming along after a class is creating and unit testing via mocks is of limited value, but it will help lock down behavior so that future changes to the class won't break expectations in surprising ways.

I hope that helps get you started.

Some mocking frameworks support mocking actual concrete classes, which can make a lot of sense in test-after unit tests (by intercepting calls to real classes not just interfaces). I couldn't find if EasyMock lets you do that, but JDave is probably the place to go if you need that kind of functionality. It even lets you mock final classes.

Yishai
+3  A: 

Something along the lines of:

import static org.easymock.classextension.EasyMock.*;

File testDir = createMock(File.class);
expect(testDir.lastModified()).andReturn(10L);
// more expectations
replay(testDir);
// create a FileMonitor watching testDir
// run the method which gets invoked by the trigger     
verify(testDir);
binil
This looks like what I am looking for. I need to play with this a bit before commenting more. Thanks for the excellent direction.
Todd
It appears that I would need to make some sort of interface for File, since EasyMock requires an interface type to mock a class. Will let you know how it goes.
Todd
Okay, back to where I was. Since I am only mocking an interface, how do I "write" to the mocked object, which is no longer of type File, but of the type of the interface?
Todd
@Todd EasyMock classextension (notice the import) can mock actual classes. The code I posted was from an actual test I wrote.
binil
@binil, sorry, missed that. We don't have the classextension here. I will see if we are allowed to use it. Meanwhile, I will get it for myself. Thanks again.
Todd
@binil, thanks, that works exactly as asked for. However, I think I asked incorrectly for what I need. The file monitor actually takes a collection of strings, indicating the paths and filenames to be monitored. It then creates a File object internally to check for lastModified, then a listener is made aware of modification. I need to create a mock File externally from which I can extract the path/name and give it to the monitor. This external file would then be (mock?) written to. Can this be done with EasyMock? Or is the File too far removed?
Todd
@Todd, if you the public interface for the class takes only Strings, you need a way to inject a mock in there, perhaps even just a factory for creating the mocked File objects. See my answer for more details on what all this means.
Yishai
@Yishai, thanks. Discussion with colleagues led to that and other options. I am trying them out.
Todd
+1  A: 

Have a look at the excellent(and concise) manual. You might reconsider using EasyMock though - most people are currently using or in the process of switching to the more advanced and more actively developed Mockito(inspired by EasyMock).

Bozhidar Batsov
Thanks for the tip. Unfortunately, I don't have a choice, it is what the company chose. As for the manual, I did read through it before asking the question, guess I missed the part about file systems.
Todd
A: 

I would put the actual call to the filesystem in its separate package-private method. For testing, extend the class and override that method. Thus you do not actually make a call to the file system.

EasyMocks classextension has also the possibility to create paritial mocks, but I'm not totally convinced of that.

http://easymock.org/EasyMock2_4_ClassExtension_Documentation.html

nebenmir