About Me

My photo
I'm project manager of a software development team at www.researchspace.com. I've been developing bioinformatics software for the last 9 years or so, and I'm hoping to share some of the experience and knowledge I've gained with Eclipse RCP, Java web app development and software development in general on these blogs.

Monday 29 September 2008

Testing selection actions in GEF (2)

In my previous blog (Testing selection actions in GEF (1), I discussed ways to test selection actions in GEF, and we got as far as testing the calculateEnabled() method.

Getting started
If you're following these blogs, this one carries straight on from the previous one. If you're diving straight in here, you can download the modified 'Shapes EXample' plugin here, and you just need to import it as a plugin project with the source code.

Now we'll move and test the run() method, again using the SrcSelectAction example.

To recap, this is the code for the action which just selects the src shape of a connection:

public void run() {
ConnectionEditPart cep = (ConnectionEditPart) getSelectedObjects().get(0);
EditPartViewer viewer = cep.getViewer();

viewer.deselectAll();
viewer.flush();
viewer.select(cep.getSource());

viewer.reveal(cep.getSource());
}
In order to test this method , we need to to a bit of work to set up viewers and edit pparts for testing. Methods called on the viewer tend to end up calling graphical code and so we need to stub out this behaviour. Again, once we have set this up we will have a good framework for testing other action classes we might write.

Creating stub classes

First of all we need to stub out the refreshVisuals() methods of edit parts.

First, create the package org.eclipse.gef.examples.shapes.parts in the 'test' folder. Then,
create the following classes in this package:


class StubConnectionEditPart extends ConnectionEditPart {
String propName;
public void propertyChange(PropertyChangeEvent event) {
this.propName = event.getPropertyName();
}

String getPropertyCalled (){
return propName;
}

}


and


class ShapeStubEditPart extends ShapeEditPart {

protected void refreshVisuals() {

}

String propName;
public void propertyChange(PropertyChangeEvent event) {
this.propName = event.getPropertyName();
}

String getPropertyCalled (){
return propName;
}
}
These are test-Spy classes - they store the details of the property change event that occurs,
and provide an accessor to those details, at the same time as stubbing out the 'visual' code.

We also need to override the EditPartFactory to create these stubs:
Copy and paste the Shapes edit part factory into the test/org.eclipse.gef.examples.shapes.parts folder, and edit the code to return
the stub edit parts.


private EditPart getPartForElement(Object modelElement) {
if (modelElement instanceof ShapesDiagram) {
return new DiagramEditPart();
}
if (modelElement instanceof Shape) {
return new ShapeStubEditPart(); //returns a stub
}
if (modelElement instanceof Connection) {
return new StubConnectionEditPart(); //returns stub
}
throw new RuntimeException(
"Can't create part for model element: "
+ ((modelElement != null) ? modelElement.getClass().getName() : "null"));
}
Finally we need to provide a stub viewer implementation which replaces the actual visual code
with test-spy methods that recored the fact the methods were called:


ViewerStub () {
setEditPartFactory(new ShapesStubEditPartFactory());
}

protected LightweightSystem createLightweightSystem() {
return null;
}

public void flush(){
timesFlushCalled++;
}

public void appendSelection(EditPart ep){
super.appendSelection(ep);
timesAppendCalled++;
}

public void reveal (EditPart ep) {
this.revealed = ep;
}
/**
* Test-spy method to check which EP was revealed.
* @return the revealed edit part
*/
public EditPart getRevealed() {
return revealed;
}



Providing a test base class
Now we need to create a framework that connects all these stubs. This class can now become a base class for all our action test classes:

package org.eclipse.gef.examples.shapes.parts;

import java.util.Map;

import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.examples.shapes.model.Connection;
import org.eclipse.gef.examples.shapes.model.EllipticalShape;
import org.eclipse.gef.examples.shapes.model.RectangularShape;
import org.eclipse.gef.examples.shapes.model.Shape;
import org.eclipse.gef.examples.shapes.model.ShapesDiagram;

/**
* Sets up a test framework for testing Selection Actions
*
* @author Richard Adams
*
*/
public class EditPartTestModelSetUp {

protected Shape LINK_TARGET, LINK_SOURCE;
protected ShapesDiagram DIAGRAM;
protected Connection CONN;

protected DiagramEditPart diagramPart;

protected ViewerStub viewerTSS = new ViewerStub();
protected GraphicalViewer viewer = viewerTSS;

protected final int NUM_ALL_SHAPES = 2;

final int NUM_LINKS = 1;

protected void generateModel() {
LINK_TARGET = new EllipticalShape();
LINK_SOURCE = new RectangularShape();
CONN = new Connection(LINK_SOURCE, LINK_TARGET);
DIAGRAM = new ShapesDiagram();
DIAGRAM.addChild(LINK_SOURCE);
DIAGRAM.addChild(LINK_TARGET);

}

protected void createEditPartList() {
generateModel();

ShapesEditPartFactory fac = new ShapesEditPartFactory();

// initialise edit part creation
diagramPart = (DiagramEditPart) fac.createEditPart(null, DIAGRAM);

// activate parent
viewer.getRootEditPart().activate();
// this creates the edit part tree
viewer.setContents(diagramPart);

}
}


This class creates a basic model, and subclasses calling createEditPartList()
will initialise the model,the edit parts and the viewer.

No comments: