1

I'm using mockito and developping with java6 and spring.

I'm working on a test API for some developpers and I propose a few methods for mocking objects and methods (it's a legacy code...). Now, I want to replace all this things by mockito but I always propose a test API. So, I developped some methods using mockito.

I have an old method with two parameters (String). A first parameter is a mocked service id and its method with parameters. And the second parameter is the returned Object. Example :

mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject);

Now, I want to use mock, when and thenReturn mockito methods, and I don't see how... Perhaps with reflection but with "when" method it's impossible because mockito need the effective method. How can I do that ? thanks.

slim
  • 447
  • 2
  • 10
  • 27
  • I fail to see why you can't use mockito directly on "the real stuff"? Is the class (or any method) you want to mock `final`? – fge Nov 24 '14 at 16:49
  • Are you asking how to parse "myServiceId.myMethod(String, Integer)"? If so I'm afraid it's not really possible. –  Nov 24 '14 at 17:06
  • 1
    I think it would be good to have a more concrete example of what are you trying to test here. A complete test method, complete scenario or smth. Is it mocking a home made mocking framework? – makasprzak Nov 24 '14 at 20:12
  • i can't use mockito directly. I'm working on a framework. It's a legacy code... i have to hide mockito for developpers because they are not required to manage versions etc. I have to parse "myServiceId.myMethod(String, Integer)" and mock the bean myServiceId and finally, return "myMethod"... For example : i have a bean "MyBean1" and inside it, another bean "MyBean2". In "MyBean1" test class, i have to mock "MyBean2" with this method : mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject); Inside it, i want to use mockito. That's all. Thanks. – slim Nov 24 '14 at 20:52
  • I don't want to mock something in an application. I'm working on a framework and developers can't use mockito directly. – slim Nov 24 '14 at 21:23

1 Answers1

4

This is a bad idea: you're trying to reimplement some of the systems Mockito already provides while losing out on many of the features Mockito offers. However, there is a way to make this work, with some difficulty. The key is to write a custom Answer, make it the default answer for the mock, and then compare your object, method name, and method parameter types using InvocationOnMock.

public class ReflectiveMockAnswer implements Answer<Object> {
  @Override public Object answer(InvocationOnMock invocation) {
    // Assume you've successfully parsed each String into a StubbedResponse, with
    // Object target, String method, String[] argTypes, and Object returnValue.
    // A Set would beat a for-loop here, should you need to optimize.
    for (StubbedResponse stubbedResponse : allStubbedResponses) {
      if (stubbedResponse.target == invocation.getMock()
          && stubbedResponse.method.equals(invocation.getMethod().getName())
          && stringArraysEqual(stubbedResponse.argTypes,
              typeNamesFrom(invocation.getMethod().getParameterTypes())) {
        return stubbedResponse.returnValue;
      }
    }
    throw new RuntimeException("Unstubbed method called.");
  }
}

// Later...
Object yourMockObject = Mockito.mock(classToMock, new ReflectiveMockAnswer());

At that point, you've implemented a simplified version of Mockito within and based on the full version of Mockito. You'll also need to:

  • Parse the string into a StubbedResponse, probably with regular expressions
  • Identify the field in your bean-under-test by name
  • Replace that field with a mock of the appropriate class, created as above, before the bean-under-test has a chance to interact with it

...and acknowledge that this solution doesn't handle:

  • Verification
  • Any sort of argument matching, including basic "equals" matching
  • Name collisions in parameter types (com.foo.SomeClass vs com.bar.SomeClass)
  • Repeated calls (thenReturn(1, 2, 3).thenThrow(new RuntimeException()))

...and cannot handle:

  • Code search tools: you can only tell which methods are mocked other than by searching for strings, not with tools like "Find references" in Eclipse the way Mockito can
  • Compile-time checking and automated refactoring tools: your tests would break at runtime if field names, method names, or parameters change; Mockito doesn't have that problem
  • Final methods: Mockito can't, so you can't either

Unless this is a "straw man" or very temporary solution, I recommend strongly to just introduce Mockito directly into your test cases, one test at a time.

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251