Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Junit for Interface default methods

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

like image 561
Jech Avatar asked Jan 22 '17 11:01

Jech


People also ask

Can we write junit test case for interface?

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.

Can we write default method in 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.

How are the methods from an interface by default?

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.

How do you call a functional interface by default method?

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.


2 Answers

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.

like image 82
heenenee Avatar answered Sep 18 '22 21:09

heenenee


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"));
    }
}
like image 20
Arpit Aggarwal Avatar answered Sep 19 '22 21:09

Arpit Aggarwal