GWTMockito UnsatisfiedLinkError

时间:2014-10-10 22:00:02

标签: gwt mocking gwtmockito

我已经完成了大部分GWT测试MVP风格,没有测试小部件。我希望能够构建更复杂的小部件并在不使用GwtTestCase(慢)的情况下对其进行测试。

出于好奇,我尝试了一个非常简单的测试。给出一个非常简单的小部件(这不是我的确切类,只是一个简化的例子):

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() }
    }
}

我正在使用GWTMockito测试,有点像这样:

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();
    }

}

我马上得到:

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 ...

你会注意到我没有使用测试运行器 - 我试过,但我正在测试的项目是使用JUnit 4.4,测试运行器似乎不适用于JUnit 4.4。如果我使用GwtMockitoTestRunner,我会得到:

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)

根据another stack overflow question和快速调查,我倾向于认为这与此项目中使用的JUnit版本有关。 GwtMockito使用BlockJunit4ClassRunner,标记为@since 4.5。

那么 - 这个测试是GWTMockito应该帮助的那种东西吗?我对GWTMockito完全不熟悉,所以很容易就是一个简单的误解,但我想理解。

我可以使用GWTMockito来测试使用Composite / IsWidget从较小的小部件构建的复杂小部件吗?不应该GWTMockito帮助我解决这个JSNI问题,还是我误读了什么?是不是因为我没有使用测试跑步者?

1 个答案:

答案 0 :(得分:2)

我看到它的方式有两种可能性:

  1. 您忘了使用GwtMockito的JUnit跑步者:

    @RunWith(GwtMockitoTestRunner.class)
    public class MyTest {
        // ...
    }
    

    如果您需要其他内容的自定义运行器,您可以在alternative way中设置GwtMockito。

  2. 您没有使用GWT.create来实例化您的小部件。

  3. 第一点很简单 - 这个跑步者是必需的,这样GwtMockito可以做到“神奇”。

    第二点需要解释:GwtMockito使用GWT的Deferred Binding。这意味着,您希望由GwtMockito 自动模拟的所有小部件必须通过调用GWT.create来实例化。使用UiBinder这很简单 - 在内部,UiBinder模板中定义的所有小部件都使用GWT.create进行实例化,因此您无需更改任何内容即可将其与GwtMockito一起使用。但是如果你没有使用UiBinder(或providing你自己的小部件实例),除非你用GWT.create实例化你的小部件,否则GwtMockito将无法发挥其魔力。

    来自GwtMockito's documentation(强调我的):

      

    GwtMockito允许您从JUnit测试中调用 GWT.create 返回Mockito模拟,从而解决了这个和其他与GWT相关的测试问题。


    更新

    我可以验证使用JUnit 4.4,跑步者抛出你提到的异常。我为此打开了issue on GwtMockito's tracker

    至于测试本身,我已经设法让它发挥作用。正如我之前提到的,GwtMockito的工作得益于Deferred Binding。意思是,你的小部件必须用GWT.create实例化 - 成员也是如此。那是GwtMockito进入你的小部件的“方式”。如果您只是致电new TextBox(),则无法用模拟替换它 如果您将MyWidget类更改为以下内容,它将通过测试(请注意对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() };
        }
    }
    

    知道这一点,有一些选择:

    • 始终记得使用GWT.create
    • 实例化复合材料中的所有小部件
    • 将它们显示为包可见(在UiBinder中的方式)并在测试中为它们分配模拟(从mockGWT.create创建)
    • 切换到UiBinder; /

    没有一个看起来太有吸引力,第一个似乎是最好的。