When Google released GWT 1.5, they slipped in a testing utility class called GWTMockUtilities. It's not very well known, in fact, it's not even in the documentation. The top hit (as of the time of writing this blog post) in a Google search for GWTMockUtilities is simply a direct link to the source code. So what is this class useful for?
Quite simply, GWTMockUtilities allows you to mock out GWT library classes using tools like JMock, Mockito, or EasyMock in your plain ol' JUnit test cases. Here's the class JavaDoc description:
Defangs GWT.create(Class) to allow unit tests to mock out Widgets and other UIObjects
OK, so it has something to do with mocking widgets in unit tests, but it's still a little cryptic. Let's look at the JavaDoc for the disarm() method:
To understand what's going on here, let's try writing a test that doesn't use GWTMockUtilities. Here's a simple test that uses JMock and tries to mock the GWT Button class. Note the setup which enables CGLIB to mock concrete classes.
@RunWith(JMock.class) public class MockingWithoutGWTMockUtilitiesTest { Mockery context = new JUnit4Mockery() {{ // Enable CGLIB mocking of concrete classes setImposteriser(ClassImposteriser.INSTANCE); }}; @Test public void mock_a_button() { // This throws an ExceptionInInitializer due to // a static initializer when loading Button Button button = context.mock(Button.class); } }
Running this test yields the following exception:
java.lang.ExceptionInInitializerError
at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:40)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:59)
at org.jmock.lib.legacy.ClassImposteriser.createProxy(ClassImposteriser.java:133)
at org.jmock.lib.legacy.ClassImposteriser.imposterise(ClassImposteriser.java:66)
at org.jmock.Mockery.mock(Mockery.java:139)
at org.jmock.Mockery.mock(Mockery.java:120)
at com.danielwellman.gwtmocks.client.MockingWithoutGWTMockUtilitiesTest.mock_a_button(MockingWithoutGWTMockUtilitiesTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
...
Caused by: java.lang.UnsupportedOperationException: ERROR: GWT.create() is only usable in client code! It cannot be called, for example, from server code. If you are running a unit test, check that your test case extends GWTTestCase and that GWT.create() is not called from within an initializer or constructor.
at com.google.gwt.core.client.GWT.create(GWT.java:91)
at com.google.gwt.user.client.ui.UIObject.<clinit>(UIObject.java:139)
... 33 more
The method GWT.create() is getting called in a static field initializer of UIObject, which happens when the JVM loads the Button class (which descends from UIObject). The exception message recommends that your test should extend GWTTestCase, the integration test case which runs JavaScript in the hosted-mode browser. But in our test we aren't using a real Button, we're just trying to make a fake one. So why should we pay the test time penalty of running in the slower GWTTestCase?
GWTMockUtilities provides you another way to solve this problem. By wrapping your test methods with GWTMockUtilities.disarm() and restore(), you can temporarily disable the harmful side effects of calling GWT.create() in a static initializer. (It turns out that all widgets cause this behavior.)
Here's a sample:
@RunWith(JMock.class) public class MockingWithGWTMockUtilitiesTest { Mockery context = new JUnit4Mockery() {{ // Enable CGLIB mocking of concrete classes setImposteriser(ClassImposteriser.INSTANCE); }}; @Before public void disableWidgets() { GWTMockUtilities.disarm(); } @After public void reEnableWidgets() { GWTMockUtilities.restore(); } @Test public void mock_a_button() { Button button = context.mock(Button.class); } }
A (slightly) more realistic example
For example, imagine the scenario of creating a dialog which prompts the user for some text. The Submit button should only be enabled when the user has actually entered something.
Here's a sample test for the Controller object, which will be given the full contents of the text field every time the user presses a key via the textChangedTo(String) method.
@RunWith(JMock.class) public class ControllerTest { Mockery context = new JUnit4Mockery() {{ // Enable CGLIB mocking of concrete classes setImposteriser(ClassImposteriser.INSTANCE); }}; @Before public void disableWidgets() { GWTMockUtilities.disarm(); } @After public void reEnableWidgets() { GWTMockUtilities.restore(); } @Test public void enables_submit_button_if_text_entered() { final Button button = context.mock(Button.class); Controller sut = new Controller(button); context.checking(new Expectations() {{ oneOf(button).setEnabled(true); }}); sut.textChangedTo("Hello"); } @Test public void disables_submit_button_if_text_cleared() { final Button button = context.mock(Button.class); Controller sut = new Controller(button); context.checking(new Expectations() {{ oneOf(button).setEnabled(false); }}); sut.textChangedTo(""); } }
Notice that we mock out our Button widget, notify the Controller that the text changed, and expect our button to be enabled or disabled appropriately.
Here's the code for the Controller which passes these tests:
public class Controller { private Button button; public Controller(Button button) { this.button = button; } /** * Callback from a form's text field onChange. * * @param newText The text entered */ public void textChangedTo(String newText) { if (isBlank(newText)) button.setEnabled(false); else button.setEnabled(true); } private boolean isBlank(String newText) { return "".equals(newText.trim()); } }
Design Implications
So when would you want to actually use GWTMockUtilities? In general, I prefer to wrap the view in an interface and mock it out in my controller tests as I wrote about in this article. However, if the controller only needs to communicate with one or two widgets as in the above example, you may want to skip creating the view interface directly and just pass in the widget directly. For me, I'd consider this an exceptional case rather than the norm, but you should do what feels natural for your applications.
Also see http://www.jmock.org/gwt.html
Posted by: Nat | April 10, 2009 at 01:30 PM
Thank you so much! this was driving me bananas!
Posted by: Marco Magdy | February 01, 2011 at 01:59 PM
Instead of mocking your widget, You could considere the gwt-test-utils framework which enable you to run your GWT client-side code in a standalone JVM.
It runs very fast in comparaison of GWTTestCase and you're not restricted to use the GWT classes white list ! For example, you can use reflection in your test to get private field within your custom widget if necessary, use EasyMock or Mockito, etc !
More information here : http://code.google.com/p/gwt-test-utils/
Posted by: Gael | June 16, 2011 at 09:51 AM
@Gael - This is an impressive project, thanks for sharing!
Posted by: Daniel Wellman | June 18, 2011 at 11:12 PM