GWTMockito UnsatisfiedLinkError



我已经完成了大部分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)

基于另一个堆栈溢出问题和快速调查,我倾向于认为这与该项目中使用的 JUnit 版本有关。GwtMockito使用BlockJunit4ClassRunner,标记为@since 4.5。

那么,这个测试是GWTMockito应该帮助的那种事情吗?我对GWTMockito完全陌生,所以这很容易成为一个简单的误解,但我想了解。

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

在我看来,有两种可能性:

  1. 你忘了使用 GwtMockito 的 JUnit 运行器:

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

    您可以通过另一种方式设置 GwtMockito,如果您需要其他内容的自定义运行器。

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

第一点很简单 - 需要这个跑步者才能让 GwtMockito 发挥它的"魔力"。

第二点需要解释:GwtMockito通过使用GWT的延迟绑定来工作。这意味着,所有你想要被 GwtMockito 自动模拟的小部件都必须通过调用 GWT.create 来实例化。这对于 UiBinder 来说很简单 - 在内部,UiBinder 模板中定义的所有小部件都使用 GWT.create 实例化,因此您无需更改任何内容即可将其与 GwtMockito 一起使用。但是,如果您不使用UiBinder(或者providing您自己的小部件实例(,则GwtMockito将无法发挥其魔力,除非您使用GWT.create实例化您的小部件。

来自 GwtMockito 的文档(强调我的(:

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


更新

我可以验证使用 JUnit 4.4 时,运行器正在抛出您提到的异常。为此,我在 GwtMockito 的跟踪器上打开了一个问题。

至于测试本身,我已经设法让它工作了。正如我之前提到的,GwtMockito的工作要归功于延迟绑定。这意味着,您的小部件必须使用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 ;/
似乎

没有一个太吸引人,第一个似乎总体上是最好的。

最新更新