Testing GWT applications using GWTTestCase can be a pain - it's slower than
using pure Java tests, and you can't use reflection-based tools like mocking
frameworks. But if you've tried to test widgets using normal test cases, you've
probably run into this error:
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.
GwtMockito solves this and other GWT-related testing problems by allowing you to call GWT.create from JUnit tests, returning Mockito mocks.
This is the YCM fork of the original google/gwtmockito, which is no longer maintained. This fork modernizes the project with:
- Mockito 5.23.0 compatibility (replaces 1.x)
- GWT 2.13.1 (
org.gwtproject) — replaces the archivedcom.google.gwt2.8.0- Java 17 source/target
- Full Mockito session lifecycle management (
openMocks/tearDown)- Automatic recovery from Mockito 5's
@InjectMocksambiguity errors on GWT base classes
Build from source and install to your local Maven repository:
git clone https://github.com/yesamer/gwtmockito.git
cd gwtmockito
mvn install -DskipTestsThen add the dependency to your project:
<dependency>
<groupId>com.google.gwt.gwtmockito</groupId>
<artifactId>gwtmockito</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>test</scope>
</dependency>Getting started with GwtMockito using JUnit 4.5+ is easy. Just annotate your test
with @RunWith(GwtMockitoTestRunner.class), then any calls to GWT.create
encountered will return Mockito mocks instead of throwing exceptions:
@RunWith(GwtMockitoTestRunner.class)
public class MyTest {
@Test
public void shouldReturnMocksFromGwtCreate() {
Label myLabel = GWT.create(Label.class);
when(myLabel.getText()).thenReturn("some text");
assertEquals("some text", myLabel.getText());
}
}GwtMockito also creates fake implementations of all UiBinders that automatically
populate @UiFields with Mockito mocks. Suppose you have a widget that looks
like this:
public class MyWidget extends Composite {
interface MyUiBinder extends UiBinder<Widget, MyWidget> {}
private final MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
@UiField Label numberLabel;
private final NumberFormatter formatter;
public MyWidget(NumberFormatter formatter) {
this.formatter = formatter;
initWidget(uiBinder.createAndBindUi(this));
}
void setNumber(int number) {
numberLabel.setText(formatter.format(number));
}
}When createAndBindUi is called, GwtMockito will automatically populate
numberLabel with a mock object. Since @UiFields are package-visible, they
can be read from your unit tests, which lets you test this widget as follows:
@RunWith(GwtMockitoTestRunner.class)
public class MyWidgetTest {
@Mock NumberFormatter formatter;
private MyWidget widget;
@Before
public void setUp() {
widget = new MyWidget(formatter);
}
@Test
public void shouldFormatNumber() {
when(formatter.format(5)).thenReturn("5.00");
widget.setNumber(5);
verify(widget.numberLabel).setText("5.00");
}
}Note that GwtMockito supports the @Mock annotation from Mockito, allowing
standard Mockito mocks to be mixed with mocks created by GwtMockito.
You can reference a mock returned by GWT.create by annotating a field with
@GwtMock. For example:
@RunWith(GwtMockitoTestRunner.class)
public class MyClassTest {
@GwtMock SomeInterface mockInterface;
@Test
public void constructorShouldSetSomething() {
new MyClass();
verify(mockInterface).setSomething(true);
}
}By default, GwtMockito will return fake implementations for any classes extending:
- UiBinder
- ClientBundle
- Messages
- CssResource
- SafeHtmlTemplates
You can add fakes for additional types by invoking
GwtMockito.useProviderForType(Class, FakeProvider) in your setUp method.
GwtMockito removes all final modifiers from classes and interfaces via its
Javassist classloader, allowing Element and other JavaScript overlay types
to be mocked:
@RunWith(GwtMockitoTestRunner.class)
public class MyTest {
@Mock Element element;
@Test
public void shouldMockFinalMethod() {
when(element.getClassName()).thenReturn("mockClass");
assertEquals("mockClass", element.getClassName());
}
}GwtMockito provides no-op implementations for all native JSNI methods:
voidmethods do nothing.- Methods returning primitive types return the default value (0, false, etc.)
- Methods returning
Strings return the empty string. - Methods returning other objects return a mock configured with
RETURNS_MOCKS.
You can use GwtMockito without GwtMockitoTestRunner by calling
GwtMockito.initMocks and GwtMockito.tearDown directly:
public class MyWidgetTest extends TestCase {
@Override
public void setUp() {
super.setUp();
GwtMockito.initMocks(this);
}
@Override
public void tearDown() {
super.tearDown();
GwtMockito.tearDown();
}
public void testSomething() {
// test code
}
}Note that when testing in this way, mocking final classes/methods and automatic native method stubs are not available.
- Upgraded to Mockito 5.23.0.
- Upgraded to GWT 2.13.1 (
org.gwtproject). - Upgraded to Java 17.
tearDown()now properly closes the Mockito session opened byopenMocks().GwtMockitoTestRunnernow callstearDown()automatically after each test.- Fixed
@InjectMockson targets extending GWT base classes (Composite,Widget) that triggered Mockito 5's ambiguity error on inherited private fields. - Fixed subclass
@Mockfield priority over same-named superclass fields. - Fixed
TypeVariablefield injection in generic base view classes. - Replaced deprecated
org.mockito.Matcherswithorg.mockito.ArgumentMatchers. - Dropped PowerMock test dependency (incompatible with Mockito 5).
- Applied Java 17 API throughout:
instanceofpattern matching,Set.of/Map.offactory methods, arrow-caseswitch, Stream API — no behaviour changes. - Eliminated
LinkedListin favour ofArrayList; deduplicated@Mock/@GwtMockfield detection into a sharedisMockField()helper. - Fixed
field.getAnnotations()→getDeclaredAnnotations()and hierarchy-walk termination to use identity check (clazz != Object.class). - Cached
getClassesToStub()per class load in the Javassist translator to avoid repeated allocations during method stubbing. - Added unit tests covering
tearDownidempotency,isGwtBaseClass,hasInjectMocksField,hasInjectMocksTargetExtendingGwtBase, andisMockField.
- Support ResourcePrototype methods in fake ClientBundles. (Thanks to zbynek)
- Add a
@WithExperimentalGarbageCollectionannotation. (Thanks to LudoP) - Updated Javassist dependency. (Thanks to TimvdLippe)
- Preliminary Java 9 support. (Thanks to benoitf)
- Update GWT to version 2.8.0.
- Update Javassist to version 3.22.
- Stubbing for ValueListBox. (Thanks to jschmied)
- Stubbing for URL encoding. (Thanks to jschmied)
- Generate hashCode and equals for Messages. (Thanks to zolv)
- See the original project changelog.