Riena/Getting Started with Controller Tests

From Eclipsepedia

Jump to: navigation, search

Riena ProjectGetting Started ▶ Controller Tests

Testing your SubModuleControllers is an essential part of assuring the quality of your client application. With Riena's Controller Testing support it is quite easy to find problems in your SubModuleController logic at an early stage.

Contents

Prerequisites

In order to set up test cases, the SubModuleController has to be prepared to acquire Ridgets without a bound view. For this the method getRidget(Class<R> ridgetClazz, String id) has to be used in the SubModuleController to test. On the one hand this method wraps getRidget(String id) to return an already known (bound) instance of the Ridget and on the other hand it creates a new instance of the Ridget if run in test mode and no bound widget is existent.

Setting up a test case

All SubModuleControllerTests should extend AbstractSubModuleControllerTest. This class provides the essential operations needed to test a controller. Every test class has to implement the abstract method createController(ISubModuleNode node) where the SubModuleController to test has to be instantiated and returned. Sometimes it is necessary to set a NavigationNode on the SubModuleController (if things like navigation or marker have to be tested). E.g.:

@Override
protected MarkerSubModuleController createController(ISubModuleNode node) {
  MarkerSubModuleController newInst = new MarkerSubModuleController();
  node.setNodeId(new NavigationNodeId("org.eclipse.riena.example.marker"));
  newInst.setNavigationNode(node);
  return newInst;
}

Testing scenarios

This section covers some in-depth examples on how to test your Controllers. More examples can be found in org.eclipse.riena.client.controller.test.

Testing Ridget behavior

The most basic things you might want to test is the logic behind Ridgets. A Ridget can be accessed by calling getController().getRidget(Class<R> ridgetClazz, String id). In addition to the normal methods that can be called on a Ridget, there are some special features for Ridgets in a Controller Test:

  • fireAction() in IActionRidget: simulates the pushing of a Button
  • triggerListener() in ITraverseRidget: simulates the "dragging" (ScaleRidget) or "clicking" (SpinnerRidget) on a TraverseRidget.


Here is an example on how to test simple correlations between Ridgets. This is a method taken from the tests for the ChoiceSubModuleController that calculates the price for certain car models with or without additional special options (see the Riena Example Client for more information):

public void testPriceAstonMartinWithOptions() {
  ISingleChoiceRidget compositeCarModel = getController().getRidget(ISingleChoiceRidget.class, "compositeCarModel");
  IMultipleChoiceRidget compositeCarExtras = getController().getRidget(IMultipleChoiceRidget.class, "compositeCarExtras");
 
  compositeCarModel.setSelection(CarModels.ASTON_MARTIN);
  compositeCarExtras.setSelection(Arrays.asList(CarOptions.FRONT_GUNS, CarOptions.UNDERWATER));
 
  assertEquals(compositeCarModel.getSelection(), CarModels.ASTON_MARTIN);
  assertEquals(compositeCarExtras.getSelection().size(), 2);
  assertEquals(compositeCarExtras.getSelection().get(0), CarOptions.FRONT_GUNS);
  assertEquals(compositeCarExtras.getSelection().get(1), CarOptions.UNDERWATER);
 
  assertEquals(getController().getCarConfig().getPrice(), 150000);
}
  1. Get the two Ridgets for the car model and the extras for that car.
  2. Set the selection of the model to CarModels.ASTON_MARTIN and set the options for that model to CarOptions.FRONT_GUNS and CarOptions.UNDERWATER.
  3. Test whether everything is selected as it should be.
  4. Test whether the calculated price of the car is 150000.

Testing the navigation

Another interesting behavior to test is the navigation between SubModuleControllers. Therefore the AbstractSubModuleControllerTest provides a mockNavigationProcessor that can be used to test several navigation conditions. Please note that all the following examples rely on a static import of org.easymock.EasyMock.*. To improve the readability the method createNavigationNode(String id) is used to create a new reference instance of a SubModuleNode.

Testing a simple navigation event

This example shows how to test whether a navigate command was executed by pressing a button.

public void testNavigateCombo() {
    expect( getMockNavigationProcessor().navigate(eq(getController().getNavigationNode()),
	                                          eq(new NavigationNodeId("org.eclipse.riena.example.navigate.comboAndList")),
					         (NavigationArgument) notNull())).andReturn(createNavigationNode("org.eclipse.riena.example.navigate.comboAndList"));
 
    replay(getMockNavigationProcessor());
 
    IActionRidget navigateToComboButton = getController().getRidget(IActionRidget.class, "comboAndList");
    navigateToComboButton.fireAction();
 
    verify(getMockNavigationProcessor());
}
  1. Call "navigate" on the mockNavigationProcessor to record it with the proper parameters. In this case the button should navigate to the SubModuleController "comboAndList" with no NavigationArgument.
  2. Replay the Mock.
  3. Get the button responsible for the navigation event and call fireAction() on it.
  4. Verify the Mock.

Testing the navigation to a specific Ridget with a NavigationArgument

Often it is necessary to navigate to a specific Ridget or even transfer an Object to it by using a NavigationArgument. Here are some examples showing different ways for different purposes.

Using an argument ridget with a ridgetID but without an object
  1. Record the navigation to org.eclipse.riena.example.combo with a NavigationArgument containing no Object but the ridgetID textFirst.
  2. Replay the mockNavigationProcessor.
  3. Get the Button and call fireAction() to initiate the navigation ini the SubModuleController.
  4. Verify the MockNavigationProcessor.
public void testNavigateToRidgetWithNotNull() {
    expect(getMockNavigationProcessor().navigate(eq(getController().getNavigationNode()),
                                                 eq(new NavigationNodeId("org.eclipse.riena.example.combo")),
						 new NavigationArgument(notNull(), "textFirst"))).andReturn(createNavigationNode("org.eclipse.riena.example.combo"));
 
    replay(getMockNavigationProcessor());
 
    IActionRidget navigateToNavigateRidget = getController().getRidget(IActionRidget.class, "btnNavigateToRidget");
    navigateToNavigateRidget.fireAction();
 
    verify(getMockNavigationProcessor());
}
Using an argument ridget with ridgetID and object, using equals(...)

This example shows how to check if the proper Object is sent to another SubModuleController using the equals(...) method of the classes involved.

Record the navigation to org.eclipse.riena.example.combo with a NavigationArgument containing a PersonModificationBean and the ridgetID textFirst by using EasyMock.eq which uses the equals method of NavigationArgument to compare.

public void testNavigateToRidgetWithEquals() {
    PersonModificationBean bean = new PersonModificationBean();
    bean.setPerson(new Person("Doe", "Jane"));
 
    expect(getMockNavigationProcessor().navigate(eq(getController().getNavigationNode()),
                                                 eq(new NavigationNodeId("org.eclipse.riena.example.combo")),
						 eq(new NavigationArgument(bean, "textFirst")))).andReturn(createNavigationNode("org.eclipse.riena.example.combo"));
 
    replay(getMockNavigationProcessor());
 
    IActionRidget navigateToNavigateRidget = getController().getRidget(IActionRidget.class, "btnNavigateToRidget");
    navigateToNavigateRidget.fireAction();
 
    verify(getMockNavigationProcessor());
}
Using an argument ridget with ridgetID and object, using a custom comparator

This example gives you some more individual control on how to compare the Object sent to another SubModuleController by using a custom compare method.

Record the navigation to org.eclipse.riena.example.combo with a NavigationArgument containing a PersonModificationBean and the ridgetID textFirst by using EasyMock.cmp(...) on the NavigationArgument. EasyMock.cmp(...) takes 3 parameters: the Object to compare, the Comparator and a LogicalOperator. In this example the Comparator compares two NavigationArguments by looking whether the two PersonModificationBeans match.

public void testNavigateToRidgetWithCompare() {
    PersonModificationBean bean = new PersonModificationBean();
    bean.setPerson(new Person("Doe", "Jane"));
 
    expect(getMockNavigationProcessor().navigate(eq(getController().getNavigationNode()),
						 eq(new NavigationNodeId("org.eclipse.riena.example.combo")),
						 cmp(new NavigationArgument(bean, "textFirst"), new Comparator<NavigationArgument>() {
 
						     public int compare(NavigationArgument o1, NavigationArgument o2) {
						         if (o1.getParameter() instanceof PersonModificationBean
							     && o2.getParameter() instanceof PersonModificationBean) {
							     return comparePersonModificationBeans((PersonModificationBean) o1.getParameter(), (PersonModificationBean) o2.getParameter());
							 } else {
							     return -1;
							 }
						     }
 
						 }, LogicalOperator.EQUAL))).andReturn(createNavigationNode("org.eclipse.riena.example.combo"));
 
    replay(getMockNavigationProcessor());
    IActionRidget navigateToNavigateRidget = getController().getRidget(IActionRidget.class, "btnNavigateToRidget");
    navigateToNavigateRidget.fireAction();
 
    verify(getMockNavigationProcessor());
}