Skip to content

Mocking RPC services

Gael Lazzari edited this page Sep 2, 2012 · 12 revisions

Frequently, your presentation layer will call remote services using GWT-RPC.
In unit tests, you will need to mock the server calls. gwt-test-utils provides an elegant way to do it, using either the EasyMock or the Mockito mocking framework.

Mocking RPC services is much like mocking any other classes, with a few specificities, like asynchronous callback handling.

Our application code

We will modify the previous sample to use GreetingService, the sample RemoteService class auto-generated when you create a new Web Application Project.

RpcSampleView.ui.xml :

<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
  <g:HTMLPanel>
    <g:TextBox ui:field="textBox"></g:TextBox>
    <g:Button ui:field="button">Say Hello</g:Button>
    <g:Label ui:field="label" />
  </g:HTMLPanel>
</ui:UiBinder> 

RpcSampleView.java:

public class RpcSampleView extends Composite {

  interface RpcSampleViewUiBinder extends UiBinder<Widget, RpcSampleView> { }
  
  private static RpcSampleViewUiBinder uiBinder = GWT.create(RpcSampleViewUiBinder.class);
  
  @UiField
  Button button;
  
  @UiField
  Label label;
  
  @UiField
  TextBox textBox;
  
  private final GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
  
  public RpcSampleView() {
    initWidget(uiBinder.createAndBindUi(this));
    label.setVisible(false);
    button.setEnabled(false);
  }
  
  @UiHandler("button")
  void onClick(ClickEvent e) {
    greetingService.greetServer(textBox.getText(), new AsyncCallback<String>() {
      public void onFailure(Throwable caught) {
        label.setText("Server error: " + caught.getMessage());
        label.setVisible(true);
      }
      
      public void onSuccess(String result) {
        label.setText(result);
        label.setVisible(true);
      }
    });
  }
  
  @UiHandler("textBox")
  void onKeyPress(KeyUpEvent e) {
    button.setEnabled(textBox.getText().trim().length() > 0);
    label.setVisible(false);
  }

}

The GreetingService servlet implementation is declared in the web.xml :

<servlet>
  <servlet-name>greetServlet</servlet-name>
  <servlet-class>com.googlecode.gwt.test.sample.server.GreetingServiceImpl</servlet-class>
</servlet>

<servlet-mapping>
  <servlet-name>greetServlet</servlet-name>
  <url-pattern>/MockSample/greet</url-pattern>
</servlet-mapping>

Clicking the button will make a server call through greetingService.greetServer(...). If it goes well, the label would greet him with the text computed server side. Otherwise, the same label would display the thrown error's message.
What we want is testing both cases by mocking the RemoteService call.

Using EasyMock

  1. Add the EasyMock maven dependency :
<dependency>
  <groupId>org.easymock</groupId>
  <artifactId>easymock</artifactId>
  <version>3.0</version>
  <scope>test</scope>
</dependency>
  1. In order to use the EasyMock mocking framework, your tests need to extend GwtTestWithEasyMock.

  2. Declare your mock RemoteService Async interface using gwt-test-utils's own @Mock annotation.

@GwtModule("com.googlecode.gwt.test.sample.MockSample")
public class RpcSampleViewWithEasyMockTest extends GwtTestWithEasyMock {

  @Mock
  private GreetingServiceAsync greetingServiceAsync;
  
  @Test
  public void clickOnButtonShouldDisplayMessageInLabelWhenRpcSuccess() {
    // Arrange
    RpcSampleView view = new RpcSampleView();
    view.textBox.setText("Ben Linus");
    view.button.setEnabled(true);
    assertThat(view.label).isNotVisible();
    
    // expect service invocation
    greetingServiceAsync.greetServer(EasyMock.eq("Ben Linus"), EasyMock.isA(AsyncCallback.class));
    expectServiceAndCallbackOnSuccess("Mocked hello message");
    
    // EasyMock.replay(..) for every @Mock objects
    replay();
    
    // Act
    Browser.click(view.button);
    
    // Assert
    // EasyMock.verify(..) for every @Mock objects
    verify();
    assertThat(view.label).isVisible().textEquals("Mocked hello message");
  }
  
  @Test
  public void clickOnButtonShouldDisplayErrorInLabelWhenRpcFailure() {
    // Arrange
    RpcSampleView view = new RpcSampleView();
    view.textBox.setText("Ben Linus");
    view.button.setEnabled(true);
    assertThat(view.label).isNotVisible();
    
    // expect service invocation
    greetingServiceAsync.greetServer(EasyMock.eq("Ben Linus"), EasyMock.isA(AsyncCallback.class));
    expectServiceAndCallbackOnFailure(new RuntimeException("expected mocked runtime exception"));
    
    // EasyMock.replay(..) for every @Mock objects
    replay();
    
    // Act
    Browser.click(view.button);
    
    // Assert
    // EasyMock.verify(..) for every @Mock objects
    verify();
    assertThat(view.label).isVisible().textEquals("Server error: expected mocked runtime exception");
  }
  
}
  • @Mock tells gwt-test-utils to create a mock object using EasyMock.

  • expectServiceAndCallbackOnSuccess(Object result) tells to make the mocked object return the "result" object as a success response to the last call.

  • expectServiceAndCallbackOnFailure(Throwable t) tells to make the mocked object return the "t" exception as a failure response to the last call.

  • replay() will call EasyMock.replay(..) on each declared @Mock in the test class.

  • verify() will call EasyMock.verify(..) on each declared @Mock in the test class.

Using Mockito

  1. Add the Mockito maven dependency :
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>1.8.5</version>
  <scope>test</scope>
</dependency>
  1. In order to use the Mockito mocking framework, your tests need to extend GwtTestWithMockito.

  2. Declare your mock objets using gwt-test-utils's or Mockito @Mock annotation.

@GwtModule("com.googlecode.gwt.test.sample.MockSample")
public class RpcSampleViewWithMockitoTest extends GwtTestWithMockito {

  @Mock
  private GreetingServiceAsync greetingServiceAsync;
  
  @Test
  public void clickOnButtonShouldDisplayMessageInLabelWhenRpcSuccess() {
    // Arrange
    RpcSampleView view = new RpcSampleView();
    view.textBox.setText("Ben Linus");
    view.button.setEnabled(true);
    assertThat(view.label).isNotVisible();
    
    // mock service succeed invocation
    doSuccessCallback("Mocked hello message").when(greetingServiceAsync).greetServer(Mockito.eq("Ben Linus"), Mockito.any(AsyncCallback.class));
    
    // Act
    Browser.click(view.button);
    
    // Assert
    Mockito.verify(greetingServiceAsync).greetServer(Mockito.eq("Ben Linus"), Mockito.any(AsyncCallback.class));
    assertThat(view.label).isVisible().textEquals("Mocked hello message");
  }
  
  @Test
  public void clickOnButtonShouldDisplayErrorInLabelWhenRpcFailure() {
    // Arrange
    RpcSampleView view = new RpcSampleView();
    view.textBox.setText("Ben Linus");
    view.button.setEnabled(true);
    assertThat(view.label).isNotVisible();
    
    // mock service failed invocation
    doFailureCallback(new RuntimeException("expected mocked runtime exception")).when(greetingServiceAsync).greetServer(Mockito.eq("Ben Linus"), Mockito.any(AsyncCallback.class));
    
    // Act
    Browser.click(view.button);
    
    // Assert
    Mockito.verify(greetingServiceAsync).greetServer(Mockito.eq("Ben Linus"), Mockito.any(AsyncCallback.class));
    assertThat(view.label).isVisible().textEquals("Server error: expected mocked runtime exception");
  }
  
}
  • @Mock tells gwt-test-utils to create a mock object using Mockito. Both gwt-test-utils or Mockito annotation can be used.

  • doSuccessCallback(Object result) tells to make the mocked object return the "result" object as a success response.

  • doFailureCallback(Throwable t) tells to make the mocked object return the "t" exception as a failure response.

  • Mockito.verify(Object mock) checks the greetServer() method was actually called with expected parameters.

Sources of this sample are available here.