Quindi il test a singola asserzione viola il DRY?
No, ma promuove la violazione.
Detto questo, un buon design orientato agli oggetti tende a uscire dalla finestra per i test unitari, principalmente per buoni motivi. È più importante che i test unitari siano isolati l'uno dall'altro in modo che il test possa essere interrogato in modo isolato e, se necessario, corretto con la sicurezza di non interrompere altri test. Fondamentalmente che la correttezza e la leggibilità del test sono più importanti della sua dimensione o manutenibilità.
Francamente, non sono mai stato un fan di una sola affermazione per regola di test per i motivi che descrivi: porta a un sacco di codice della caldaia che è difficile da leggere, facile da usare in modo errato e difficile da correggere bene se si refacturing (che ti spinge a refactoring meno).
Se si suppone che una funzione restituisca un elenco di "pippo" e "barra" per un dato input, ma in qualsiasi ordine è perfettamente corretto usare due asserzioni per verificare che entrambi siano nel set di risultati. Il punto in cui ti trovi nei guai è quando un singolo test sta controllando due ingressi o due effetti collaterali e non sai quale dei due ha causato l'errore.
Lo considero una variazione del Principio della singola responsabilità: dovrebbe esserci solo una cosa che può far fallire un test, e in un mondo ideale quel cambiamento dovrebbe superare solo un test.
Ma alla fine è un compromesso. Hai più probabilità di dedicare più tempo a mantenere tutto il codice copia incolla, o passerai più tempo a cercare le cause alla radice quando i test potrebbero essere interrotti da più fonti. Fintanto che scrivi alcuni test, probabilmente non importa troppo. Nonostante il mio disprezzo per i test a singola asserzione, tendo a sbagliare sul lato di più test. Il tuo chilometraggio può variare.