Stai confrontando 2 tipi di test: unit test e test di integrazione. I test unitari dovrebbero essere veloci. A me piacciono i test unitari per eseguire una frazione di secondo. Questo è importante quando si esegue ripetutamente un test durante la scrittura / modifica del codice. Per rendere veloce il test delle unità, il test non può chiamare alcuna risorsa remota o accedere a un database. Sicuramente, non si desidera avviare un server di chat nel test dell'unità.
I test unitari dovrebbero aiutarti anche con il refactoring. È meglio farlo quando il tuo test unitario va solo al confine architettonico più vicino. Si prova che si raggiunge il confine e si passa il messaggio corretto oltre il confine. Puoi anche verificare che il tuo codice gestisca correttamente tutto ciò che può essere restituito da oltre il confine. In questo modo il tuo sistema è liberamente accoppiato e mutevole - e così anche i tuoi test.
Oltre ai test unitari, si verifica anche che il sistema interagisca correttamente oltre i limiti e con altri sistemi. Le persone chiamano questi test di interazione o test di integrazione. Potrebbero richiedere più tempo per l'esecuzione perché in genere eseguono l'accesso remoto e potrebbero anche essere necessario avviare un'istanza di test di un server. Poiché hai già disaccoppiato i tuoi layer in test di unità, non è necessario testare ogni possibile permutazione di input e output nei test di integrazione. Ogni test di integrazione dura più a lungo, ma ne hai meno.
Mettendo tutto insieme, ti suggerisco di creare test di unità "piccoli" per il tuo ChatService, ChatNotificationDelegate e così via, andando solo fino al prossimo servizio. È possibile prendere in giro l'altro servizio per verificare che l'oggetto del test passi i parametri corretti oltre i limiti e reagisca correttamente ai resi. Mirerai a ottenere un'alta copertura dei test unitari. Inoltre, avrai un piccolo numero di test di integrazione che funzionano su un unico limite. O forse anche un solo fine per terminare il test di invio del messaggio, come suggerito.
Quindi la mia risposta a
test every bit we know exactly what went wrong, or to make my tests as
general as possible (just the endpoints) to allow more freedom of
refactoring the code
è entrambi: molti piccoli test di unità per sapere esattamente cosa è andato storto e un grande test di integrazione per assicurarsi che tutti i pezzi combacino. E vorrei dire che un singolo test end-to-end non "consente la libertà di refactoring". Il contrario è spesso vero. Un test di una scatola nera può dirti che qualcosa non va, ma non hai idea di cosa si sia rotto esattamente. Se il sistema può rompersi misteriosamente, senza un modo semplice per identificare o almeno individuare la causa principale, è più probabile che teme di apportare modifiche significative, come il refactoring.