Mockito - mocking classes with native methods
Asked Answered
A

2

14

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?

Advection answered 19/4, 2012 at 7:45 Comment(0)
L
13

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.

Lockhart answered 19/4, 2012 at 7:51 Comment(5)
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.Advection
When you wrap someone else's stuff then you have the control. :-) That's the beauty of wrappers, adapters, or façades.Lockhart
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 :(.Advection
@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)? https://mcmap.net/q/830928/-testing-code-which-calls-native-methodsLockhart
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!Advection
A
1

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);
    }
}
Abound answered 8/8, 2016 at 15:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.