Dire che ho una classe seguente:
public class A {
public void execute() {
if (something)
ThirdPartyApi.method();
}
}
Ora vorrei testare in particolare il metodo execute()
. Voglio assicurare che tutti i percorsi sono coperti e funzionano come previsto. Tuttavia, il problema che vorrei eseguire qui non è in grado di prendere in giro il ThirdPartyApi
perché non è fornito come dipendenza. Una facile soluzione a questo è di fornire ThirdPartyApi
come una dipendenza come questa.
public class A {
private ThirdPartyApi api;
public A(ThirdPartyApi api) {
this.api = api;
}
public void execute() {
if (something)
api.method();
}
}
Ora vorrei ottenere la funzionalità che voglio e tutti sarebbero felici. Tuttavia, ciò che non mi piace qui è il fatto che ho bisogno di fornire tutte le dipendenze interne attraverso un metodo costruttore / set per rendere la mia classe completamente testabile e indipendente da qualsiasi dipendenza esterna (API Android, librerie, utility, ecc.) .
Questo diventa un problema per le dipendenze che non sono direttamente necessarie per realizzare il caso d'uso della classe. Si tratta di un semplice strumento, ad esempio lo strumento di conversione delle unità. In questo modo, chiedo all'utente di questa classe di fornirmi una dipendenza che posso creare internamente per conto mio. Rende l'API più difficile da usare, perché l'utente deve sapere di più sulla classe di quanto dovrebbe / necessario.
Per rendere l'esempio più specifico, dì che ThidPartyApi
è un'enorme libreria di conversione di unità esterne. Perché un utente dovrebbe fornirmi una classe da questa libreria attraverso un costruttore? È qualcosa che è un semplice strumento secondario utilizzato per realizzare il caso d'uso. Non è direttamente correlato al caso d'uso stesso. Richiedere questa dipendenza in un costruttore renderebbe l'API più confusa. Vedi la seguente lezione:
public class Storage {
private ConversionTool api;
public Storage (ConversionTool api) {
this.api = api;
}
public void storeInteger(int a) {
storeString(api.convertToString(a));
}
}
vs
public class Storage {
private ConversionTool api;
public Storage () {
this.api = new ConversionTool();
}
public void storeInteger(int a) {
storeString(api.convertToString(a));
}
}
Quale sarebbe l'approccio preferito? Fornire dipendenze secondarie tramite il costruttore rende più verificabile e controllabile, ma l'API perde il suo significato. Non fornire dipendenze secondarie attraverso il costruttore mantiene il significato in una classe, ma perdo la capacità di prendere in giro tutto all'interno della classe e testare completamente la classe.