12

I have simple test case:

@Test
public void test() throws Exception{
       TableElement table = mock(TableElement.class);
       table.insertRow(0);
}

Where TableElement is GWT class with method insertRow defined as:

public final native TableRowElement insertRow(int index);

When I launch test I'm getting:

java.lang.UnsatisfiedLinkError: com.google.gwt.dom.client.TableElement.insertRow(I)Lcom/google/gwt/dom/client/TableRowElement;
    at com.google.gwt.dom.client.TableElement.insertRow(Native Method)

Which as I believe is related with insertRow method being native. Is there any way or workaround to mock such methods with Mockito?

Piotr Sobczyk
  • 6,443
  • 7
  • 47
  • 70

2 Answers2

12

Mockito itself doesn't seem to be able to mock native methods according to this Google Group thread. However you do have two options:

  1. Wrap the TableElement class in an interface and mock that interface to properly test that your SUT calls the wrapped insertRow(...) method. The drawback is the extra interface that you need to add (when GWT project should've done this in their own API) and the overhead to use it. The code for the interface and the concrete implementation would look like this:

    // the mockable interface
    public interface ITableElementWrapper {
        public void insertRow(int index);
    }
    
    // the concrete implementation that you'll be using
    public class TableElementWrapper implements ITableElementWrapper {
        TableElement wrapped;
    
        public TableElementWrapper(TableElement te) {
            this.wrapped = te;
        }
    
        public void insertRow(int index) {
            wrapped.insertRow(index);
        }
    }
    
    // the factory that your SUT should be injected with and be 
    // using to wrap the table element with
    public interface IGwtWrapperFactory {
        public ITableElementWrapper wrap(TableElement te);
    }
    
    public class GwtWrapperFactory implements IGwtWrapperFactory {
        public ITableElementWrapper wrap(TableElement te) {
            return new TableElementWrapper(te);
        }
    }
    
  2. Use Powermock and it's Mockito API extension called PowerMockito to mock the native method. The drawback is that you have another dependency to load into your test project (I'm aware this may be a problem with some organizations where a 3rd party library has to be audited first in order to be used).

Personally I'd go with option 2, as GWT project is not likely to wrap their own classes in interfaces (and it is more likely they have more native methods that needs to be mocked) and doing it for yourself to only wrap a native method call is just waste of your time.

schnatterer
  • 7,525
  • 7
  • 61
  • 80
Spoike
  • 119,724
  • 44
  • 140
  • 158
  • Unfortunately I have no control over `TableElement` class - it belongs to external library. However Powermock Mockito API extension looks very interesting, I'll check it out. – Piotr Sobczyk Apr 19 '12 at 07:56
  • 1
    When you wrap someone else's stuff then **you** have the control. :-) That's the beauty of wrappers, [adapters](http://en.wikipedia.org/wiki/Adapter_pattern), or [façades](http://en.wikipedia.org/wiki/Facade_pattern). – Spoike Apr 19 '12 at 08:23
  • Thanks a lot for very good and detailed answer. Wrapping will work and I may use it as a last resort but for my taste it's too much leaning and complicating production code only for test purposes :(. – Piotr Sobczyk Apr 19 '12 at 08:30
  • @PiotrSobczyk Did it work? I read you had some problems with PowerMock before you edited your comment. Are you sure you are calling things correctly (happens often)? http://stackoverflow.com/a/4916474/3713 – Spoike Apr 19 '12 at 08:37
  • Yeah, it works now. I forgot to include @PrepareForTest(TableElement.class), that's why didn't worked. Thank you once again, you were very helpful! – Piotr Sobczyk Apr 19 '12 at 08:57
0

In case anybody else stumbles about this: In the meantime (in May 2013) GwtMockito turned up, which solves this problem without PowerMock's overhead.

Try this

@RunWith(GwtMockitoTestRunner.class)
public class MyTest {

    @Test
    public void test() throws Exception{
        TableElement table = mock(TableElement.class);
        table.insertRow(0);
    }
}
schnatterer
  • 7,525
  • 7
  • 61
  • 80