javagwtjunitgwtpjukito

GWT Timer UnsatisfiedLinkError when testing with Jukito


I'm using Jukito to test a GWTP Presenter and in one of those that has a timer as a field for a repeating task I'm having this exception thrown.

I'm running GWT 2.8.2, GWTP 1.6, JUnit 4 and Jukito 1.5

The test looks like this:

@RunWith(JukitoRunner.class)
public class MyPresenterTest {

    @Inject
    MyPresenter presenter;

    @Test
    public void prepareFromRequestTest(EventBus eventBus,
                                       MyServiceAsync MyService) {

        PlaceRequest placeRequest = new PlaceRequest.Builder()
                .nameToken(NameTokens.getMyPlace())
                .with("aParam", "0110")
                .build();

        Data data = DataTestFactory.createData();

        AsyncStubber.callSuccessWith(data)
                .when(myService)
                .requestDataToServer(eq("0110"), any());

        // the timer scheduleRepeating is called in here:
        presenter.prepareFromRequest(placeRequest);
    }
}

Even a basic test like the following fails:

@RunWith(JukitoRunner.class)
public class GwtTimerTest {

    @Test
    public void testTimer() {
        Timer timer = new Timer() {
            @Override
            public void run() {
                System.out.println("timer");
            }
        };

        timer.schedule(1000);
    }
}

This is the full exception:

java.lang.UnsatisfiedLinkError: com.google.gwt.user.client.Timer.createCallback(Lcom/google/gwt/user/client/Timer;I)Lcom/google/gwt/core/client/JavaScriptObject;

at com.google.gwt.user.client.Timer.createCallback(Native Method)
at com.google.gwt.user.client.Timer.schedule(Timer.java:98)
at my.test (Redacted.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.jukito.InjectedStatement.evaluate(InjectedStatement.java:108)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:305)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:365)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:330)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:78)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:328)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:65)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:292)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:305)
at org.junit.runners.ParentRunner.run(ParentRunner.java:412)
at org.jukito.JukitoRunner.run(JukitoRunner.java:227)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

I suppose I could catch an Error (UnsatisfiedLinkError is not in JRE Emulation of GWT) but that would not let me test properly what happens after the timer is scheduled. Anyone can reproduce it or have any idea how to fix it?


Solution

  • Avoid using Timer and use com.google.gwt.core.client.Scheduler instead. Then you can bind an actual scheduler in prod code, and the StubScheduler in tests.

    You can make Timer works using gwtmockito, but I as you are already using injection, you really should hide any native or GWT.create call behind abstractions, and use alternative implementation for tests.