GWTMockito UnsatisfiedLinkError
I have done most of my MVP test in GWT without validating widgets. I would like to be able to create more complex widgets and test them well without using GwtTestCase
(slow).
Out of curiosity, I tried a very simple test. Given a very simple widget, a bit like this (this is not my exact class, just a simplified example):
public class MyWidget extends Composite {
private TextBox boxOne, boxTwo;
public MyWidget() {
boxOne = new TextBox();
boxTwo = new TextBox();
VerticalPanel panel = new VerticalPanel();
panel.add( boxOne );
panel.add( boxTwo );
initWidget( panel );
}
public String[] getText() {
return new String[] { boxOne.getText(), boxTwo.getText() }
}
}
And I use the GWTMockito test a bit:
public class MyWidgetTest {
private ConstantsWithLookup constants;
private MyWidget widget;
@Before
public void createMocks() {
GwtMockito.initMocks( this );
constants = mock( ConstantsWithLookup.class );
}
@Test
public void testIsInvalidByDefault() {
widget = new MyWidget( constants ) {
protected void initWidget(Widget w) {
// Disarm for testing
}
};
assertNotNull( widget );
}
@After
public void tearDown() {
GwtMockito.tearDown();
}
}
I immediately get:
java.lang.UnsatisfiedLinkError: com.google.gwt.dom.client.Document.nativeGet()Lcom/google/gwt/dom/client/Document;
at com.google.gwt.dom.client.Document.nativeGet(Native Method)
at com.google.gwt.dom.client.Document.get(Document.java:46)
at com.google.gwt.user.client.ui.TextBox.<init>(TextBox.java:78)
at mypackage.MyWidget.<init>(MyWidget.java:linenumber)
... etc ...
You will notice that I am not using a test runner, I tried, but the project I tested is using JUnit 4.4, the test runner doesn't seem to work with JUnit 4.4. If I use GwtMockitoTestRunner I get:
java.lang.NoSuchFieldError: NULL
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:57)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:57)
at com.google.gwtmockito.GwtMockitoTestRunner.<init>(GwtMockitoTestRunner.java:114)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
Based on another Stack Overflow question , and also a quick investigation, I tend to believe it has something to do with the JUnit version used in this project. GwtMockito uses BlockJunit4ClassRunner
which is marked @since 4.5.
So - is this test what GWTMockito is supposed to help? I am completely new to GWTMockito, so this could easily be a simple misunderstanding, but I would like to understand.
Can I use GWTMockito to test complex widgets made from smaller widgets with Composite
/ IsWidget
? Didn't GWTMockito help me with this JSNI question or am I misunderstanding something? Is it just because I am not using a test runner?
source to share
As I see it, there are two possibilities:
-
You forgot to use the GwtMockito JUnit runner:
@RunWith(GwtMockitoTestRunner.class) public class MyTest { // ... }
You can set GwtMockito to an alternate path if you need a custom runner for something different.
-
You don't use
GWT.create
to create your widgets.
The first point is simple: this runner is required for GwtMockito to perform its "magic".
The second point needs some explanation: GwtMockito works using GWT Deferred Binding . This means that all the widgets you want to automatically mock GwtMockito must be created by calling GWT.create
. It's straight forward with UiBinder - internally, all the widgets defined in the UiBinder template are created with GWT.create
, so you don't need to change anything to use it with GwtMockito. But unless you are using UiBinder (or providing
your own widget instances), GwtMockito cannot work its magic unless you create your widgets with GWT.create
.
From the GwtMockito Documentation (emphasis mine):
GwtMockito solves this and other GWT-related testing problems by letting you call GWT.create from JUnit tests returns Mockito mocks .
Update
I can verify that as of JUnit 4.4, the runner is throwing the exception you mentioned. I opened a question in the GwtMockito tracker for this.
As far as the test itself is concerned, I managed to get it to work. As I mentioned earlier, GwtMockito works thanks to Deferred Binding. This means your widgets must be created with GWT.create
members. This is the GwtMockito "path" to your widget. If you just call it new TextBox()
, it won't be able to replace that with a mock.
If you change your MyWidget class to the following, it will pass the test (note the calls GWT.create
).
public class MyWidget extends Composite {
private TextBox boxOne, boxTwo;
public MyWidget() {
boxOne = GWT.create(TextBox.class);
boxTwo = GWT.create(TextBox.class);
VerticalPanel panel = GWT.create(VerticalPanel.class);
panel.add( boxOne );
panel.add( boxTwo );
initWidget( panel );
}
public String[] getText() {
return new String[] { boxOne.getText(), boxTwo.getText() };
}
}
Knowing this, there are several options:
- always remember to create all the widgets in your composites with
GWT.create
- expose them as visible packages (as you do in UiBinder) and assign them to mocks (created from
mock
orGWT.create
) in your tests - switch to UiBinder; /
No, it seems too attractive, the former seems to be the best overall.
source to share