Mocking Eclipse IResource.accept()

I am currently involved in making the ClearCase plug-in for Eclipse, the one hosted at SourceForge, a bit better. Part of the job consists of creating unit tests to make sure that my fixes will stay fixed.

One interesting problem was that in some of my tests, I had to mock the org.eclipse.core.resources.IResource interface. Nothing too hard about that, just write the following code, using EasyMock 2.4:

protected void setUp() throws Exception {
   resource1 = createMock("resource1", IResource.class);
   resource2 = createMock("resource2", IResource.class);

Now to my problem. First, I will discuss what the IResource.accept(IResourceVisitor visitor) metod does:
The IResource.accept(…) method traverses the directory structure under the resource. For each resource found, starting with the IResource on which accept() was called, the visitor.visit(IResource resource) method is called. If the visit(…) method returns true, the directory structure under the resource is traversed, otherwise traversing stops for that specific resource. This way parts of the directory structure under an IResource can be visited.

The problem I encountered was that since I have an IResource mock, there is no code for the accept() method. The mock will just register that there has been a call for accept(), but the code in the IResourceVisitor.visit(IResource resource), which I want tested, is never called.

What to do? There are different solutions, one example is to use an implementation of IResource, for example org.eclipse.core.internal.resources.Folder, and create a partially mocked object and keep the code for accept(). Not a nice solution though, my test would depend on internal code in the Eclipse project. What I did instead was to use the org.easymock.EasyMock.expectLastCall().andAnswer(IAnswer answer) functionality. The andAnswer() method takes an IAnswer callback implementation, like this:

public void testCollectRefreshStatus() throws CoreException {
   // Normal mock expects

   // Provide code for accept(...)
   expectLastCall().andAnswer(new IAnswer() {
      public Object answer() throws Throwable { // 1.
        IResourceVisitor visitor = (IResourceVisitor) EasyMock.getCurrentArguments()[0]; // 2.
        visitor.visit(resource2); // 3.
        return null;
   expect(resource2.getName()).andReturn("file.txt"); // 4.


   // Perform test

   // Verify test
   assertEquals(1, myTestTarget.getNumberOfResources());

Here are some comments to the marked lines in the code above:

1. The answer() method is dictated by the IAnswer interface.
2. EasyMock provides a method to get access to the objects sent as parameters for the expected call. In this case, the call is resource1.accept(…) and the parameter is the IResourceVisitor implementation defined in myTestTarget, which is the code that should be tested.
3. Here the test code has control of the call to the IResourceVisitor.visit() and a mock IResource is provided as parameter. To make the test even better, the boolean return value from the visit() call should be saved and asserted for the correct value to ensure that the intended traversing works as expected.
4. Here the expectations on the mock IResource, for the visit(IResource …) call, is defined. In this case myTestTarget calls getName() on IResource for some reason, so expectations for that is defined together with a resulting return value that would steer the logic in some direction.

This way the test has full control of the visitor implementation and it is fairly easy to test all the criterias that makes the IResourceVisitor.visit(…) implementation return true or false. Also, the visit() method often changes state of something else, and here it is also possible to test that the state is changed correctly by simulating multiple visit(…) calls, by adding more calls to visit at 3. in the code above.

/Tobias Södergren

Leave a Reply