mockcentral: GWT sample project example
This example use of MockCentral enhances the sample
project presented in the Large scale application development and MVP
article from the Google Web Toolkit site. It consists of an update of the testing code in the
com.google.gwt.sample.contacts.test.ExampleJRETest
class in the project's "test" source directory and a MockCentral configuration file
defining a number of mock objects. Eclipse is required.
This example has been tested using Eclipse Helios, GWT SDK 2.0.4, JUnit 3, JDK 1.6.0 and the MockCentral 2.0.0 Eclipse plugin and server versions.
project setup
- Download the sample project, unzip it and use the "File --> Import...--> General --> Existing Projects Into Workspace" command, choose "Browse" and navigate to the extracted folder. Click "OK" and "Finish".
- Download and install the MockCentral Eclipse plugin and restart Eclipse.
- download and install the required .jar files in the project's "lib" folder. These include commons-beanutils, commons-digester, commons-logging, log4j, mockcentral-server and mockobjects-core (for convenience, any MockCentral download supplies all of these in its own "lib" folder).
- Add these libraries to the project's build path: from Eclipse's "Project" menu, select "Properties... Java Build Path... Libraries" and click the "Add Jars..." button to update the build path.
- With the "Properties" dialog still open, tab to the "Order and Export" page and move the jar files you just added up in the list so that they appear above the GWT SDK library (this is important to ensure the the MockCentralServer has access to the required versions of these libraries).
- Set up logging for the project: import the "log4j.properties" file supplied in the MockCentral download into the project's "war/WEB-INF" folder.
-
Copy the test case code from here
and paste it into the
ExampleJRETest.javafile, replacing the orginal contents. -
Follow the steps below in the "building the configuration file" section to create the
MockCentral-config.xml file (or simply download this mockcentral-config.xml
file for the test case and import it into the
com.google.gwt.sample.contacts.testpackage under the "test" source directory). -
Select the
ExampleJRETest.javafile in the Package Explorer view, right click and choose "Run As... JUnit Test".
building the configuration file
-
In the package explorer, right-click the
com.google.gwt.sample.contacts.testpackage and select "New --> File...--> Other...--> MockCentral --> MockCental config file". Accept the defaults in the wizard that opens and click "Finish". If the file doesn't open automatically in the MockCentral editor, right-click on it now and choose "Open With ---> MockCentral Editor." - Create a new fixture by clicking the "New" button in the editor. Name the new fixture "baseFixture" and click "Finish". Use the outline view to expand the nodes and select "mock objects."
- Add a new mock definition by clicking the "New" button in the editor. Enter "mockRpcService" for the name and then click "choose..." to select the mock interface. Begin typing "ContactServiceAsync" and select the name from the "matching items" list when it shows up. Click "Next >" to view the mockable methods for the interface. Deslect all except the "getContactDetails" method and click finish.
- Navigate back to the "mock objects fixtures" node and add a new fixture, naming it "testBindFixture". Add a mock object definition named "mockHandlerRegistration". Assign "HandlerRegistration" as the interface. No need to define any method expectations for this mock, just click "Finish".
- Add a mock object definition named "mockAddButton", with "HasClickHandlers" as the interface. Click "Next >", leave the "addClickHandler" method checked, but uncheck the "fireEvent" method and click "Next >" Select "expect-return" for the method expectation type and click "Finish".
- Expand the tree in the Outline view for the new mock and click on the "addClickHandler" node under "expectations". Click the "Edit" button next to the "Result" display to open the result editor. Choose "Mock Object reference" for the value type and enter "mockHandlerRegistration".
- Right-click the "mockAddButton" node in the Outline view and select "Copy". Right-click the "mock objects" node and click "Paste", assigning the name "mockDeleteButton" for the new mock. Paste another copy, naming it "mockList".
- Create another mock definition called "mockDisplay" with interface "Display" (com.google.gwt.sample.contacts.client.presenter.ContactsPresenter$Display). Add expectations for the "getAddButton", "getDeleteButton" and "getList" methods. As described in step 7 above, edit the return values for each of these methods, selecting "mock object" from the drop-down and typing in the appropriate mock name.
- Copy and paste "testBindFixture" to duplicate it, and name the copy "testGoFixture". Navigate the the "expectations" node under the "mockDisplay" node in the outline view. Use the "New" button to add an expectation for the "asWidget" method.
- Copy and paste the "mockRpcService" mock definition into the mock list for "testGoFixture". Update the method expecation for "getContactDetails" to "expect-return".
- Create a new fixture named "testContactSortFixture". Add a single mock for the "Display" interface, naming it "mockDisplay". No method expectations are needed.
The configuration file is now ready for use in our test case.
the test case
package com.google.gwt.sample.contacts.test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
import org.mockcentral.server.MockCentralServer;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.sample.contacts.client.ContactsServiceAsync;
import com.google.gwt.sample.contacts.client.domain.ContactDetails;
import com.google.gwt.sample.contacts.client.presenter.ContactsPresenter;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
/**
* Test case for the ContactsPresenter class in the GWT demo app presented in
* the "Building Large Scale Applications and MVP Part 1" article. This test
* case uses MockCentral to quickly and easily define Mock Object fixtures
* enabling greater code coverage.
*/
public class ExampleJRETest extends TestCase {
/* the MockCentralServer singleton for the test case */
MockCentralServer server = MockCentralServer.getInstance();
/* the ContactsServiceAsync Mock */
private ContactsServiceAsync mockRpcService;
/* the HandlerManager instance used for constructing presenters */
private HandlerManager eventBus = new HandlerManager(null);
/*
* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() {
// load the server up with the mocks
InputStream is = getClass().getResourceAsStream("mockcentral-config.xml");
server.init(is);
// assign the ContactsServiceAsync used to construct the
// ContactsPresenter instances throughout the test case
mockRpcService = (ContactsServiceAsync) server.getProxy("baseFixture",
"mockRpcService");
}
/**
* Test for the ContactsPresenter.bind() method
*/
public void testBind() {
// assign the mock ContactsPresenter.Display for this test
ContactsPresenter.Display mockDisplay = (ContactsPresenter.Display) server
.getProxy("testBindFixture", "mockDisplay");
// instantiate a new ContactsPresenter
ContactsPresenter contactsPresenter = new ContactsPresenter(
mockRpcService, eventBus, mockDisplay);
// invoke the bind method
contactsPresenter.bind();
// assert that the addClickHandler method was called on each of the mock
// HasClickHandlers objects defined in the class. These mocks all have
// "expect and return" expectations for the method
server.verifyMock("testBindFixture", "mockAddButton");
server.verifyMock("testBindFixture", "mockDeleteButton");
server.verifyMock("testBindFixture", "mockList");
}
/**
* Test for the ContactsPresenter.go(final HasWidgets container) method
*/
public void testGo() {
// assign the ContactsServiceAsync used to construct the
// ContactsPresenter instance for this test. Here we want to
// use "expect and return" for the fetchContactDetails method of this
// interface so we can perform a verification. We therefore override the
// mockRpcService assignment in the setUp() method used for the other tests.
mockRpcService = (ContactsServiceAsync) server.getProxy("testGoFixture",
"mockRpcService");
// assign the mock ContactsPresenter.Display for this test
ContactsPresenter.Display mockDisplay = (ContactsPresenter.Display) server
.getProxy("testGoFixture", "mockDisplay");
// instantiate a new ContactsPresenter
ContactsPresenter contactsPresenter = new ContactsPresenter(
mockRpcService, eventBus, mockDisplay);
// create a new HasWidgets instance for use in testing the method (note
// that this interface cannot me mocked within a non-GWTTest due to
// restrictions enforced by the GWT.create() method. Thus we make use of
// a custom implementation defined in this class (HasWidgetsTestingImpl)
// to run our test, which additionally allows us to make some assertions
HasWidgetsTestingImpl mockContainer = new HasWidgetsTestingImpl();
// assert that the methods called from ContactsPresenter.go(final
// HasWidgets container) haven't been called yet
assertFalse(mockContainer.clearInvoked);
assertFalse(mockContainer.addInvoked);
// invoke the method
contactsPresenter.go(mockContainer);
// assert that the fetchContactDetails in the ContactsServiceAsync was
// called
server.verifyMock("testGoFixture", "mockRpcService");
// assert that the methods called from ContactsPresenter.go(final
// HasWidgets container) were invoked
assertTrue(mockContainer.clearInvoked);
assertTrue(mockContainer.addInvoked);
}
/**
* Test for the ContactsPresenter.sortContactDetails() method. This test is
* essentially the same as the one supplied in the sample project.
*/
public void testContactSort() {
// assign the mock ContactsPresenter.Display
ContactsPresenter.Display mockDisplay = (ContactsPresenter.Display) server
.getProxy("testContactSortFixture", "mockDisplay");
// instantiate a new ContactsPresenter
ContactsPresenter contactsPresenter = new ContactsPresenter(mockRpcService, eventBus, mockDisplay);
// create a list of ContactDetail instances
List<ContactDetails> contactDetails = new ArrayList<ContactDetails>();
contactDetails.add(new ContactDetails(0l, "c_contact"));
contactDetails.add(new ContactDetails(1l, "b_contact"));
contactDetails.add(new ContactDetails(2l, "a_contact"));
// assign the list and invoke the method
contactsPresenter.setContactDetails(contactDetails);
contactsPresenter.sortContactDetails();
// assert the proper sorting took place
assertTrue(contactsPresenter.getContactDetail(0).getDisplayName().equals("a_contact"));
assertTrue(contactsPresenter.getContactDetail(1).getDisplayName().equals("b_contact"));
assertTrue(contactsPresenter.getContactDetail(2).getDisplayName().equals("c_contact"));
}
/*
* a HasWidgets implementation used for testing.
*/
private class HasWidgetsTestingImpl implements HasWidgets {
// a flag set to true when the add(Widget) method gets invoked
boolean addInvoked = false;
// a flag set to true when the clear() method gets invoked
boolean clearInvoked = false;
/*
* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasWidgets#add(com.google.gwt.user.
* client.ui.Widget)
*/
@Override
public void add(Widget w) {
// update the boolean value
addInvoked = true;
}
/*
* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasWidgets#clear()
*/
@Override
public void clear() {
// update the boolean value
clearInvoked = true;
}
/*
* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasWidgets#iterator()
*/
@Override
public Iterator<Widget> iterator() {
return null;
}
/*
* (non-Javadoc)
* @see com.google.gwt.user.client.ui.HasWidgets#remove(com.google.gwt.user
* .client.ui.Widget)
*/
@Override
public boolean remove(Widget w) {
return false;
}
}
}
