Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bug in Mockito with Grails/Groovy

I am using Mockito 1.9 with Grails 1.3.7 and I have a strange bug.

The following test case in java works:

import static org.mockito.Mockito.*;

public class MockitoTests extends TestCase {

    @Test
    public void testSomeVoidMethod(){
        TestClass spy = spy(new TestClass());
        doNothing().when(spy).someVoidMethod();
    }

    public static class TestClass {

        public void someVoidMethod(){
        }
    }
}

This test in groovy does not work:

import static org.mockito.Mockito.*

public class MockitoTests extends TestCase {

    public void testSomeVoidMethod() {
        def testClassMock = spy(new TestClass())
        doNothing().when(testClassMock).someVoidMethod()
    }

}

public class TestClass{

    public void someVoidMethod(){
    }
}

This is the error message:

only void methods can doNothing()!
Example of correct use of doNothing():
    doNothing().
    doThrow(new RuntimeException())
    .when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
org.mockito.exceptions.base.MockitoException: 
Only void methods can doNothing()!
Example of correct use of doNothing():
    doNothing().
    doThrow(new RuntimeException())
    .when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:129)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:146)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)

Does anymone observed the same error?

like image 598
Peter Avatar asked Feb 21 '12 09:02

Peter


1 Answers

The problem is Groovy is intercepting your method call before it reaches someVoidMethod. The method actually being called is getMetaClass which is not a void method.

You can verify this is happening by replacing:

doNothing().when(testClassMock).someVoidMethod()

with:

doReturn(testClassMock.getMetaClass()).when(testClassMock).someVoidMethod()

I'm not sure you will be able to get around this issue using stock Mockito and Groovy.

like image 170
seth.miller Avatar answered Oct 17 '22 08:10

seth.miller