AbtPst
AbtPst

Reputation: 8008

Mockito : How to ignore transitive dependencies

I am using mockito for my unit tests. Consider the following snippet

ThirdPartyClass tpo = mock(ThirdPartyClass.class);
doNothing().when(tpo).someMethod();

ThirdPartyClass is from a third party jar, lets say tp.jar. Now tp.jar is not an uber jar. Here is what ThirdPartyClass looks like

class ThirdPartyClass
{
    SomeOtherClass memberObject;

    public ThirdPartyClass(){}

    /*Rest of the code*/
}

Now, when i try to run my unit tests, i get java.lang.ClassNotFoundException for SomeOtherClass. Remember that tp.jar is not an uber jar so it makes sense that SomeOtherClass is not in my classpath.

But why is mockito not able to handle this transitive dependency? Is there any way to ignore all transitive dependencies?

Upvotes: 1

Views: 1798

Answers (3)

Lovis
Lovis

Reputation: 10047

"Only mock types that you own" is the way to go here.
One reason for that is exactly what you describe: the test set up becomes too complicated, e.g. because of dependencies.

So instead of mocking the ThirdPartyClass, you create some sort of Adapter and then mock that class.

interface ThirdPartyAdapter {
   void someMethod(); // only put method here that you really use
}

And then mock that thing instead:

ThirdPartyAdapter tpo = mock(ThirdPartyAdapter.class);
doNothing().when(tpo).someMethod();

And in production, delegate to the ThirdPartyClass:

class UsefulThing implements ThirdPartyAdapter {
   ThirdPartyClass wrapped;

   UsefulThing(ThirdPartyClass wrapped) {
     this.wrapped = wrapped;
   }

   @Override
   void someMethod() {
     wrapped.someMethod()
   }
}

Benefits:

  • Tests and production code is more robust to changes of the third party classes
  • You can use your own domain terms for methods instead of what the third party dictates
  • The relationship between your code and the third party code becomes clearer (and is only visible at a single place in your code)

I highly recommend Growing Object Oriented Software by Freeman & Pryce - or check the mockito docks for a quick start.

Upvotes: 7

lance-java
lance-java

Reputation: 27976

If you are going to mock ThirdPartyClass then SomeOtherClass MUST be on your compile-time and runtime classpath. Without seeing how you are building/running it's difficult to give real help

You need to ensure that all the required classes (jars) are on

  1. The compile classpath
  2. The runtime classpath

If you are using a build tool like Gradle or Maven to build & run then the classpaths, including transitive dependencies, will be managed for you. If you are compiling/running by hand you will need to ensure that the transitive dependencies are on the compile-time & runtime classpaths.

Upvotes: 1

Tobb
Tobb

Reputation: 12180

Mockito works by creating a subclass of the class to be mocked. So the class to be mocked has to compile. Could perhaps be solved by adding the jar that contains SomeOtherClass to your dependency management with scope test.

Upvotes: 4

Related Questions