Please help in writing Junit for the interface default method.
public interface ABC {
default List getSrc(DEF def, XYZ xyz) t
I think there is a simpler way. It consists in implementing the interface with methods to be tested in the test class and invoking methods of default type directly. If necessary, the objects that are called internally are mocked. The previous example would be such that:
Interface)
public interface ABC<T, D, K, V> {
default List<String> getSrc(DEF def, XYZ xyz) throws Exception {
list<String>() result=new Arraylist<String>();
result.add(def.toString());
result.add(xyz.toString());
return result;
}
}
Test class)
...
@RunWith(MockitoJUnitRunner.class)
public class ABCTest implements ABC{
@Test
public void testGetSrc() {
list<String>() result=getSrc(new DEF("Hi!"),new XYZ("bye!"));
int actual=result.size();
int expected=2;
assertEquals(expected, actual);
}
If you need to test the launch of an exception, it will be enough to force its release from wrong parameters and correctly configure the test:
...
@Test(expected = GenericRuntimeException.class)
public void test....
...
I've checked it with a similar code and it works. It is also collected correctly in the coverage analysis.
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're using Mockito, the simplest way to unit-test a default (AKA "defender") method is to make a spy1 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.
You can either create a class that implements your interface or make your test implement it. The second one seems to be a shorter solution:
public class FunctionCallingTransactionTemplateTest implements FunctionCallingTransactionTemplate {
private final Object object = Mockito.mock(Object.class);
@Test
public void should_invoke_function() throws Exception {
// given
when(object.toString()).thenReturn("salami");
// when
String result = functionCallingTransactionTemplate().execute((status) -> object.toString());
// then
assertThat(result).isEqualTo("salami");
}
}
The answer is very straight forward. No mocking or spying needed for this just create an anonymous object for interface without overriding default methods.
Ex:
interface Adder {
default sum(Integer...n) {
return Arrays.stream(n).reduce(0, Integer::sum);
}
}
// Junit 4
class AdderTest {
private Adder adder;
@Before
public void setup() {}
adder = new Adder(){}; // not overriding default methods
}
@Test
public void testSum() {
Assert.assertEquals(3, adder.sum(1, 2));
}
}