Unit testing similar wrappers - or single unit test is enough?

by maestro   Last Updated November 09, 2018 00:05 AM

I'm working on a service which has a lots of dependencies. The way how I call them is I'm wrapping each service client around an Adapter. Like this (I'm using Java):

public abstract class AdapterBase<Request, Response> {
    protected abstract String adapterMetadata();
    protected abstract Response makeActualCall(Request request);

    public Optional call(Request request) {
        try {
            return Optional.ofNullable(makeCall(request));
        } catch(Exception ex) {
            log.error("bad thing happened", ex);
            return Optional.empty();
        }
    }
}

Now, for each API I'm calling, I'm creating a new adapter, and for each adapter, I'm creating a new unit test.

A sample implementation of this AdapterBase:

public class FooAdapter<FooRequest, FooResponse> extends AdapterBase<FooRequest, FooResponse> {
    private FooClient fooClient;            
    public FooAdapter(FooClient fooClient) {
        this.fooClient = fooClient;
    }

    @Override
    protected String adapterMetadata() {
        "Calling Foo";
    }

    @Override
    protected FooResponse makeActualCall(FooRequest fooRequest) {
        return fooClient.call(fooRequest);
    }
}

And I have the similar inherited classes for each API. The basic unit test for this concrete FooAdapter would be the following:

@RunWith(MockitoJUnitRunner.class)
public class FooAdapterTest {
    @Mock
    private FooClient fooClient;

    @Mock
    private FooResponse fooResponse;

    private FooAdapter fooAdapter;

    @Before
    public void setup() {
        fooAdapter = new FooAdapter(fooClient);
    }

    @Test
    public void whenExceptionIsThrownThenEmptyObservableReturns() {
        when(fooClient.call(any()).thenThrow(FooException.class);

        Optional<FooResponse> actual = fooAdapter.call(new FooRequest());

        assertFalse(actual.isPresent());
    }

    @Test
    public void whenCallSucceededThenResultReturns() {
        when(fooClient.call(any()).thenReturn(fooResponse);

        Optional<FooResponse> actual = fooAdapter.call(new FooRequest());

        assertTrue(actual.isPresent());
        assertEquals(fooResponse, actual.get());
    }
}

And for all the concrete adapters, I have the same unit tests. At this point, I'm wondering if these unit tests are holding any value to us. It's all the same, the only difference is that different "clients" can throw different exceptions, but because of the implementation of AdapterBase, it doesn't really matter what exception it was.

Having these classes are obviously increasing test-coverage metric, but I'm not 100% convinced on what value we are getting out of it. I'm thinking of changing this to one artificial implementation of the AdapterBase and I only have one single unit test against it, since all the adapters are following the same pattern.

I was reading that too many very low-level unit tests might be an obstacle against agile changes since it requires lots of code changes in non-production-related codebase. However, each adapter is a single unit, therefore it has to be tested.

I'm curious about what would be the right way to follow in this case.



Related Questions


Updated July 13, 2016 08:02 AM

Updated June 21, 2017 22:05 PM

Updated November 03, 2017 14:05 PM

Updated November 04, 2017 23:05 PM

Updated June 06, 2015 01:02 AM