So does single-assertion testing violate DRY?
No, ma promuove la violazione.
Detto questo, il buon design orientato agli oggetti tende a uscire dalla finestra per i test unitari, soprattutto per una buona ragione. È 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, risolto con la certezza che non si rompono altri test. Fondamentalmente la correttezza e leggibilità del test è più importante delle sue dimensioni o manutenibilità.
Francamente, non sono mai stato un fan di quello che asserisco per regola di test per i motivi che descrivi: porta a un sacco di codice standard difficile da leggere, facile da falsare e difficile da risolvere bene se si refactoring (che ti spinge a refactoring di meno).
Se si suppone che una funzione restituisca un elenco di "foo" e "bar" per un dato input, ma in qualsiasi ordine è perfettamente corretto usare due asserzioni per verificare che entrambi siano nel set di risultati. Dove ti trovi nei guai è quando un singolo test sta controllando due input o due effetti collaterali e non sai quale dei due ha causato l'errore.
Lo vedo come una variazione del Principio di Responsabilità Unica: dovrebbe esserci solo una cosa che può far fallire un test, e in un mondo ideale che il cambiamento dovrebbe interrompere solo un test.
Ma alla fine è un compromesso. È più probabile che tu spenda più tempo a mantenere tutto il codice di copia incolla, o passerai più tempo a cercare le cause principali quando i test potrebbero essere interrotti da più fonti. Finché scrivi - alcuni test, probabilmente non importa troppo. Nonostante il mio disprezzo per i test monodimensionali, tendo a sbagliare sul lato di altri test. Il tuo chilometraggio può variare.