Q:

unit testing default method calling abstract method in an interface

I have an interface which has two methods - convertList and convert.
convertList has a default implementation that calls convert for each input in its inputList.
I want to write a unit test for convertList that -

test if it calls convert method as many times as the size of inputlist
test if it passes on convertedOutput object for each input to the list of convertedOutputs

Following is my interface -
public interface MyConverter {
    ConverterOutput convert(final MyDTO input, final String myParam) throws MyDTOConversionException;

    default Collection<ConverterOutput> convertList(
        final Collection<? extends MyDTO> inputList,
        final String myParam)
        throws MyDTOConversionException {
        try {
            List<ConverterOutput> converterOutputs = new ArrayList<>();

            for (MyDTO input : inputList) {
                converterOutputs.add(this.convert(input, myParam));
            }
            return converterOutputs;
        } catch (NullPointerException npe) {
            throw new MyDTOConversionException("Unable to convert dto to converter output", npe);
        }
    }
}

I am unable to achieve 1 while mocking the interface and stubbing its convert method. Following is my test class.
@SpringBootTest(classes = MyConverter.class)
public class MyConverterTest extends BaseTest {

    class MyDTOImpl extends MyDTO {
        @Override
        public void someAbstractMethod(String param) {
        }
    }

    @Mock
    private ConverterOutput converterOutput;

    @Mock
    private MyConverter myConverter;

    @Mock
    private MyDTOImpl myDTO;

    @Test
    public void testConvertListOfSizeOne() {

        String myParam = "1234";

        Collection<MyDTO> myDTOS = new ArrayList<>();
        myDTOS.add(myDTO);

        try {
            when(myConverter.convert(myDTO, myParam)).thenReturn(converterOutput);
            Collection<ConverterOutput> actualConverterOutputs = myConverter.convertList(myDTOS, myParam);

            // check if times convert method was called is as expected
            verify(myConverter, times(1)).convert(myDTO, myParam);

            // check if number of items in output object are as expected
            Assert.assertEquals(actualConverterOutputs.size(), 1);

            // check if output object is as expected
            for (ConverterOutput c: actualConverterOutputs) {
                Assert.assertSame(c, converterOutput);
            }
        } catch (MyDTOConversionException exception) {
            throw new AssertionError("MyDTOConversionException should not have occurred");
        }
    }
}

Following is the error I got

Wanted but not invoked: myConverter.convert(myDTO, "1234");
  -> at com.abc.project.converters.MyConverterTest.testConvertListOfSizeOne(MyConverterTest.java:49)
However, there were other interactions with this mock:
  myConverter.convertList(
      [myDTO],
      "1234" );

A:

Two things helped me fix the issue.
One, add an inner class that implements MyConverter interface as simply using Mock annotation seems to override the default method too and I was unable to ask Mockito to call original default method implementation.
class MyConverterImpl implements MyConverter {
    MyConverterImpl() {}
    @Override
    public ConverterOutput apply(final MyDTO input, final String myParam)
            throws MyDTOConversionException {
        return converterOutput;
    }
}

Next, explicitly ask Mockito to call the real method
when(myConverter.convertList(myDTOS, myParam)).thenCallRealMethod();

Without this, default implementation of convertList was not getting called.

