【问题标题】:GWTMockito UnsatisfiedLinkErrorGWTMockito UnsatisfiedLinkError
【发布时间】:2014-10-10 22:00:01
【问题描述】:

我已经完成了我的大部分 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 问题,还是我误读了什么?只是因为我没有使用测试运行器吗?

【问题讨论】:

  • 你能发布失败的测试吗?你确定你使用的是GwtMockitoTestRunner
  • 嗨@Wiseman 你能解决这个问题吗?
  • 我已经太久记不住细节了——尽管我知道有问题的项目最终没有采用 GwtMockito。这是否是因为我没有找到让我对GwtMockito 感到满意的东西,都已经消失在时间的迷雾中。 ;)

标签: gwt mocking gwtmockito


【解决方案1】:

在我看来,有两种可能:

  1. 您忘记使用 GwtMockito 的 JUnit 运行器:

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

    如果您需要自定义运行程序来完成其他任务,您可以在 alternative way 中设置 GwtMockito。

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

第一点很简单——这个跑步者是必需的,这样 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 ;/

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

【讨论】:

  • 我正在使用另一种方法(减去'initWidget'块,这对我没有任何意义,因为我正在测试的复合材料中没有定义该方法)。当然,我可能仍然遗漏了一些重要的东西。 ;)
  • 我会说这是你的问题 - 正如 GWTMockito 的文档所说:“当实例化一个小部件时,测试还必须继承它并使用无操作实现覆盖 initWidget,否则它将失败此方法尝试调用 Javascript”。 GwtMockitoTestRunner 会自动为您执行此操作(我仍然不明白您为什么不使用它 - 它应该与 JUnit 4.4 一起使用)。你能把MyWidget的来源也发一下吗?
  • 出于某种原因,我觉得composite 没有定义initWidget(),这显然不是真的。我将不得不恢复测试并重试,看看是否能解决问题。我在我的问题中包含了一个简化的小部件,并对我在 Junit v4.4 中遇到的错误进行了一些澄清(类似于stackoverflow.com/questions/7688395/…,但当我重试时可以获得真正的堆栈跟踪)
  • initWidgetComposite 中最重要的方法之一;) 请尝试按照文档“解除”它并报告回来。至于 JUnit 4.4 - 如果可以重新创建错误,那么您可以将其提交给 GwtMockito 的issue tracker,因为他们声称支持 JUnit 4,所以我认为应该包括 4.4...
  • 我会根据你的更新再试一次,但你已经非常有帮助了,所以我会根据你已经投入的内容为你提供答案。 :) 我不喜欢您提出的任何选项,但似乎这些是使 GwtMockito 与复合材料一起工作的方法。
猜你喜欢
  • 2015-04-24
  • 2012-05-28
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
相关资源
最近更新 更多