Sono nuovo nell'adozione di un approccio completamente TDD che utilizza la DI così da poter prendere in giro ogni dipendenza. Uno dei punti critici che ho identificato finora è il fatto che ogni volta che lavoro nel mio costruttore, ogni test deve prepararsi a quella sequenza (aspettarsi le corrispondenti chiamate simulate). Un esempio di tale sequenza potrebbe essere la creazione di un messaggio di invio o il controllo dell'esistenza di una cartella, ecc.
Esistono buone pratiche su come gestire tali situazioni. Giusto, considero le due opzioni:
- Nessun lavoro nel costruttore (ingombrante dal momento che ho bisogno di manualmente per assicurarmi che gli invarianti dell'oggetto siano soddisfatti)
- Verifica individualmente la sequenza di avvio e lavora solo con oggetti intializzati nel test
Non sono riuscito a trovare approfondimenti su google come questi problemi vengono gestiti in generale. Sto seguendo un principio di progettazione scadente?
Modifica, Esempio aggiunto:
struct CachedObservable {
INJECT(CachedObserable(
std::shared_ptr<IO> io,
std::shared_ptr<Observable> base
))
{
load_and_emit_cached_file_from_hdd_if_available(io);
base->subscribe([this](auto& x) {
save_value_in_file(cached_filepath);
emit(x);
});
}
void load_and_emit_cached_file_from_hdd_if_available(
std::shared_ptr<IO> io
)
{
if (io->file_exists(cached_filepath))
emit(io->load(cached_filepath));
}
...
};
L'esempio è un'astrazione ma cattura il caso d'uso reale. Io uso frutta e amp; rxcpp per avere un oggetto di riproduzione che faccia due cose:
- Durante la costruzione carica un valore memorizzato nella cache da un file sull'HDD ed emette il contenuto
- Inoltra tutti i valori emessi dall'osservabile inserito e memorizza nella cache l'ultimo oggetto
Uso i mock sia per io che osservabili per isolare completamente il comportamento della classe