You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Krzysztof Mackowiak (Jira)" <ji...@apache.org> on 2021/05/25 14:53:00 UTC

[jira] [Created] (CAMEL-16658) AmbiguousMethodCallException when using Mockito mock as bean for camel-bean component.

Krzysztof Mackowiak created CAMEL-16658:
-------------------------------------------

             Summary: AmbiguousMethodCallException when using Mockito mock as bean for camel-bean component.
                 Key: CAMEL-16658
                 URL: https://issues.apache.org/jira/browse/CAMEL-16658
             Project: Camel
          Issue Type: Bug
          Components: camel-bean
    Affects Versions: 3.x
            Reporter: Krzysztof Mackowiak
         Attachments: Tests_-_AmbiguousMethodCallException_when_using_Mockito_mock_as_bean_for_camel-bean_compon.patch

In Camel 2.x camel-bean component considered only public methods when trying to choose a method to call.

In Camel 3.x this behaviour was changed and now protected and package methods are also considered (it was implemented in the CAMEL-13298 task).

Unfortunately this change causes that using Mockito mocks as beans for camel-bean components (for example to test some Camel routes) causes an AmbiguousMethodCallException to be thrown.

Here is an example of such exception:
{code:java}
org.apache.camel.component.bean.AmbiguousMethodCallException: Ambiguous method invocations possible:
[public java.lang.String org.apache.camel.component.bean.MockitoMockForClassTest$MyService$MockitoMock$1368359973.doSomething(java.lang.String),
final java.lang.String org.apache.camel.component.bean.MockitoMockForClassTest$MyService$MockitoMock$1368359973.doSomething$accessor$MJMz0OHK(java.lang.String)]
on the exchange: Exchange[]
  at org.apache.camel.component.bean.BeanInfo.chooseBestPossibleMethodInfo(BeanInfo.java:887)
  ...
{code}
 

This is caused by the fact that Mockito adds package level methods with the same argument list to created mock/spy.

Additional complication is added by the fact that Mockito 1.x (which uses CGLIB underneath) adds different methods than Mockito 2.x and 3.x (which uses Byte Buddy).

Here are 3 JUnit tests that reproduce this problem:
{code:java}
// NOTE: fails for Mockito 3.x and 2.x, but passes for Mockito 1.x
public class MockitoMockForClassTest extends ContextTestSupport {

    @Test
    public void testCallingMock() throws Exception {
        Object response = template.requestBody("direct:start", "anything");
        assertEquals("mocked answer", response);
    }

    @Override
    protected Registry createRegistry() throws Exception {
        MyService mockService = Mockito.mock(MyService.class);
        when(mockService.doSomething(any())).thenReturn("mocked answer");

        Registry answer = super.createRegistry();
        answer.bind("myService", mockService);
        return answer;
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from("direct:start").bean("bean:myService");
            }
        };
    }

    public class MyService {
        public String doSomething(String body) {
            return "real answer";
        }
    }

}
{code}
{code:java}
// NOTE: fails for Mockito 3.x and 2.x, but passes for Mockito 1.x
public class MockitoSpyForClassTest extends ContextTestSupport {

    @Test
    public void testCallingSpy() throws Exception {
        Object response = template.requestBody("direct:start", "anything");
        assertEquals("mocked answer", response);
    }

    @Override
    protected Registry createRegistry() throws Exception {
        MyService mockService = Mockito.spy(new MyService());
        when(mockService.doSomething(any())).thenReturn("mocked answer");

        Registry answer = super.createRegistry();
        answer.bind("myService", mockService);
        return answer;
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from("direct:start").bean("bean:myService");
            }
        };
    }

    public class MyService {
        public String doSomething(String body) {
            return "real answer";
        }
    }

}
{code}
{code:java}
// NOTE: fails for Mockito 1.x, but passes for Mockito 3.x and 2.x
public class MockitoMockForInterfaceTest extends ContextTestSupport {

    @Test
    public void testCallingMock() throws Exception {
        Object response = template.requestBody("direct:start", "anything");
        assertEquals("mocked answer", response);
    }

    @Override
    protected Registry createRegistry() throws Exception {
        MyService mockService = Mockito.mock(MyService.class);
        when(mockService.doSomething(any())).thenReturn("mocked answer");

        Registry answer = super.createRegistry();
        answer.bind("myService", mockService);
        return answer;
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            public void configure() throws Exception {
                from("direct:start").bean("bean:myService");
            }
        };
    }

    public interface MyService {
        String doSomething(String body);
    }

}
{code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)