What are Mockito Extra Interfaces?
Mockito is my favored little helper if it comes down to write light weight JUnit tests. It is very useful to replace the ‘real’ dependencies of a unit under test easily by mocks if necessary. In particular when working on the borderline to framework APIs such dependencies can otherwise be very expensive to setup.
But sometimes the situation is a bit more complicated. E.g. if the test needs to interact for some reason at least with one real instance that belongs to such a framework. If this interaction includes passing a mock as parameter to this instance, on hard luck the implementation casts the parameter to a type that is unknown from the interactor’s point of view.
Here is a simple example to clarify this:
public interface Foo { [...] } public class Bar { public Bar( Foo foo ) { Runnable runnable = ( Runnable )foo; runnable.run(); } [...] } public class SomeTest { @Test public void testConstructor() { Foo fooMock = mock( Foo.class ); // fails with ClassCastException Bar bar = new Bar( fooMock ); [...] } }
Think of the class Bar
as framework code that expects a certain kind of implementation. As the parameter type Foo
does not reflect this expectation passing a mock of Foo
to the constructor of Bar
will cause the test to fail with a ClassCastException
.
Maybe the first thought that comes to your mind when looking at the situation above is that the framework sucks by casting to an undeclared type and that one is better off by throwing everything away and starting all over again ;-)
Testing with JUnit
Testing with JUnit is one of the most valuable skills a Java developer can learn. No matter what your specific background, whether you’re simply interested in building up a safety net to reduce regressions of your desktop application or in improving your server-side reliability based on robust and reusable components, unit testing is the way to go.
Frank has written a book that gives a profound entry point in the essentials of testing with JUnit and prepares you for test-related daily work challenges.
Unfortunately there are real world situations where such a behavior is arguably valid. The Eclipse platform for example has a lot of interfaces that are declared as ‘not intended to be implemented by clients’. A good example for this is the IHistoryView
interface of the team API. Working with the 3.x platform one can be pretty sure that the IHistoryView
implementation extends IViewPart
, although this is a detail that is not exposed by the history view interface.
Given this circumstances, occasionally it might be desirable to create a mock of multiple types – a mock that implements IHistoryView
and IViewPart
– although the API does not indicate all of them. Mockito facilitates this via the lesser-known MockSettings#extraInterfaces
mock configuration capability. The following snippet shows how to use extraInterfaces
to fix the test of the example above.
@Test public void testConstructor() { Foo mock = mock( Foo.class, withSettings().extraInterfaces( Runnable.class ) ); // the mock now supports the cast to runnable Bar bar = new Bar( mock ); [...] }
The method call withSettings
creates a new instance of MockSettings
that gets configured with the additional Runnable
type. The generated Foo
mock instance implements both Foo
and Runnable
. And now the test passes.
However keep in mind that although the motivation for the usage of extra interfaces in this post might seem plausible, it cannot be stressed enough that you should really consider twice before actually using this feature. Or as the documentation states ‘If you happen to use it often than please make sure you are really producing simple, clean & readable code.’ And carelessly used it is definitely a predetermined breaking point.
- Xmas Clean Sheet Update (0.9) - 21. December 2021
- Clean Sheet Service Update (0.8) - 23. May 2020
- Clean Sheet Service Update (0.7) - 24. April 2020
[…] => What are Mockito Extra Interfaces? […]
Perfect this is just what I was looking for. Didn’t even know this existed.
Hi,
I am facing one issue regarding casting. Appreciate help.
code snippet :
import com.attunity.adapter.core.CoreDomRecord;
import javax.resource.cci.MappedRecord;
I am having follwoing things in my code :
Element outEl = ((CoreDomRecord) ctrl).getDom();
NodeList SSA58501List = outEl.getElementsByTagName(“PROD_DTL”);
where ctrl is mocked object which is cast to CoreDomRecord which is real class so after doing casting with various ways available on internet , i am getting class cast exception.
Kindly help how would i do mocking for below code :
Element outEl = ((CoreDomRecord) ctrl).getDom();
Don’t know if I understand the problem correctly but it seems as if the MappedRecord double simply isn’t a CoreDomRecord. Maybe you should create a double of CoreDomRecord if this is possible. But as a side note keep in mind, that it is usually not a good practice creating doubles of classes that you do not own.
I am getting following error :
java.lang.ClassCastException: $javax.resource.cci.MappedRecord$$EnhancerByMockitoWithCGLIB$$a3b6c9eb cannot be cast to com.attunity.adapter.core.CoreDomRecord
Interesting but why you dont simple find the class or another interface that implements both interfaces and mock that one. :)
Lucky if you have such class, but there might be cases where there isn’t a class that implements the necessary interfaces. Mockito’s extra interfaces are meant for exactly that case when there is no such class or it isn’t desirable or possible to mock such class.