Please help in writing Junit for the interface default method.
public interface ABC<T, D, K, V> {
default List<String> getSrc(DEF def, XYZ xyz) throws Exception {
}
}
ABC: Interface Name. DEF and XYZ: Class Name
You can use an abstract test case to test an interface with common tests independent of implementation, and then generate concrete instances of the test case for each implementation of the interface.
Interfaces can have default methods with implementation in Java 8 on later. Interfaces can have static methods as well, similar to static methods in classes. Default methods were introduced to provide backward compatibility for old interfaces so that they can have new methods without affecting existing code.
Like regular interface methods, default methods are implicitly public; there's no need to specify the public modifier. Unlike regular interface methods, we declare them with the default keyword at the beginning of the method signature, and they provide an implementation.
A class can override a default interface method and call the original method by using super , keeping it nicely in line with calling a super method from an extended class. But there is one catch, you need to put the name of the interface before calling super this is necessary even if only one interface is added.
If you're using Mockito, the simplest way to unit-test a default (AKA "defender") method is to make a spy
1 using the interface class literal2. The default method can then be invoked on the returned spy instance as normal. The following example demonstrates:
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
interface OddInterface {
// does not need any unit tests because there is no default implementation
boolean doSomethingOdd(int i);
// this should have unit tests because it has a default implementation
default boolean isOdd(int i) {
return i % 2 == 1;
}
}
public class OddInterfaceTest {
OddInterface cut = spy(OddInterface.class);
@Test
public void two_IS_NOT_odd() {
assertFalse(cut.isOdd(2));
}
@Test
public void three_IS_odd() {
assertTrue(cut.isOdd(3));
}
}
(tested with Java 8 and mockito-2.24.5)
1People often warn using a spy
can be indicative of a code or test smell, but testing a default method is a perfect example of when using a spy
is a good idea.
2As of the time of this writing (2019), the signature of spy
which accepts a class literal is marked as @Incubating
, but has been around since mockito-1.10.12 which was released in 2014. Furthermore, support for default methods in Mockito has been around since mockito-2.1.0 which was released in 2016. It seems like a safe bet that this method will continue to work in future versions of Mockito.
As suggested in the answer, create implementation class for the interface and test it, for an example I modified getSrc
method in your ABC
interface, as below:
import java.util.ArrayList;
import java.util.List;
public interface ABC<T, D, K, V> {
default List<String> getSrc(DEF def, XYZ xyz) {
final List<String> defaultList = new ArrayList<>();
defaultList.add("default");
defaultList.add("another-default");
return defaultList;
}
}
Created an implementation class for the same, optionally you can create another method calling super method and write @Test
for both, as I does:
import java.util.List;
public class ABCImpl implements ABC<String, Integer, String, Integer> {
public List<String> getSrcImpl(DEF def, XYZ xyz) {
final List<String> list = getSrc(def, xyz);
list.add("implementation");
return list;
}
}
Corresponding Test class for the implementation is as follows:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
public class ABCImplTest {
private ABCImpl abcImpl;
@Before
public void setup() {
abcImpl = new ABCImpl();
}
@Test
public void testGetSrc() throws Exception {
List<String> result = abcImpl.getSrc(new DEF(), new XYZ());
assertThat((Collection<String>) result, is(not(empty())));
assertThat(result, contains("default", "another-default"));
}
@Test
public void testABCImplGetSrc() throws Exception {
List<String> result = abcImpl.getSrcImpl(new DEF(), new XYZ());
assertThat((Collection<String>) result, is(not(empty())));
assertThat(result, contains("default", "another-default", "implementation"));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With