Sto lavorando a un servizio che ha molte dipendenze. Il modo in cui li chiamo è che sto avvolgendo ogni client di servizio su un Adapter
. Come questo (sto usando Java):
public abstract class AdapterBase<Request, Response> {
protected abstract String adapterMetadata();
protected abstract Response makeActualCall(Request request);
// additional things are happening here, for each dependency call it's the same
public Optional<Response> call(Request request) {
try {
return Optional.ofNullable(makeCall(request));
} catch(Exception ex) {
log.error("bad thing happened", ex);
return Optional.empty();
}
}
}
Ora, per ogni API che sto chiamando, sto creando un nuovo adattatore e per ogni adattatore sto creando un nuovo test dell'unità.
Un'implementazione di esempio di questo 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);
}
}
E ho le classi ereditate simili per ogni API. Il test unitario di base per questo calcestruzzo FooAdapter
sarebbe il seguente:
@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());
}
}
E per tutti gli adattatori di cemento, ho gli stessi test di unità. A questo punto, mi chiedo se questi test unitari non abbiano alcun valore per noi. È la stessa cosa, l'unica differenza è che diversi "client" possono generare eccezioni diverse, ma a causa dell'implementazione di AdapterBase
, non importa quale sia stata l'eccezione.
Avere queste classi sta ovviamente aumentando la metrica di copertura dei test, ma non sono convinto al 100% su quale valore ne ricaviamo. Sto pensando di cambiarlo con un'implementazione artificiale di AdapterBase
e ho solo un test unitario contro di esso, poiché tutti gli adattatori stanno seguendo lo stesso schema.
Stavo leggendo che troppi test unitari di livello molto basso potrebbero essere un ostacolo alle modifiche agili poiché richiedono molte modifiche al codice nella base di codice non correlata alla produzione. Tuttavia, ogni adattatore è una singola unità, quindi deve essere testato.
Sono curioso di sapere quale sarebbe il modo giusto di seguire in questo caso.