Tylko właściwie jest to gorsze, bo łamiąc enkapsulację przynajmniej przetestujesz to co kod robi (ściśle bo ściśle, testy rigid, tight-coupling, ale przynajmniej przetestujesz). Z takimi metodami diagnozującymi nie wiesz czy testujesz faktyczny kod, czy testujesz tylko te metody diagnozujące, a to co robi kod jest nieprzetestowane.
Nie, to jest praktycznie to samo. Różni się lokalizacją kodu testowego. Metoda diagnostyczna jest formalnie częścią testu, natomiast właśnie ze względu na czytelność kodu lepiej ją mieć bliżej danych na których działa. I metoda diagnostyczna powinna być oznaczona jako testowa, w produkcie końcowym jej nie ma.
To po co ta metoda ma w ogóle być w kodzie produkcyjnym, czemu po prostu nie przenieść jej do testów?
Poza tym, nawet jak nie zrobiliśmy testów w TDD; nadal możemy łatwo sprawdzić czy test działa. Jeśli znajdziemy test który sprawdza jakąś funkcjonalnośc, wystarczy specjalnie dodać buga, i sprawdzić czy test sfailuje - jeśli tak, to jest wartościowy. Jeśli nie, to ma buga w sobie albo jest redundant, i można go wyrzucić (zakładając że dodaliśmy tego buga, i widać w aplikacji że ten bug jest).
To nie gwarantuje braku bugów.
Oczywiście że nie. Żadna metoda nie gwarantuje braku bugów. Ale niektóre metody są lepsze niż inne do ich ograniczenia. Moim zdaniem TDD jest jedną z lepszych (jak nie najlepszą).
Nadal możesz mieć niepoprawny test działający na niepoprawnym kodzie, który przechodzi na zielono.
Możesz napisać najpierw niepoprawny test, a potem niepoprawny kod, który go przechodzi. Sytuacja identyczna jak z metodami diagnostycznymi. Identyczna, bo kod diagnostyczny i tak stosujesz - są częścią testów. To jest tylko kwestia organizacji kodu, semantycznie niczym się nie różni.
Nie sądzę że jesteś w stanie to zrobić. A przynajmniej jest to bardzo trudne.
Weź pod uwagę:
- Piszesz test (zły, ale jeszcze tego nie wiesz)
- Odpalasz test, i on ma nie przejść
- Piszesz mały kawałek kodu produkcyjnego
- Odpalasz zły test, i on teraz przechodzi po dopisaniu tego małego kawałka logiki
Bardzo trudno byłoby napisać zły test który najpierw by sfailował, a potem po dopisaniu odpowiedniej logiki by przeszedł. Właśnie na tym polega cała moc TDD. Owszem, znajdą się takie przypadki pewnie raz na tysiąc, ale to można wtedy bezproblemowo poprawić kolejnym testem.
Jest to możliwe, ale zakłada że programista popełni dwa błedy po sobie - najpierw pisząc test, potem pisząc kod; i to jeszcze takie błędy które nawzajem się enforce'ują (tzn brak kodu == fail, dodanie kodu == pass). To jest niesamowicie rzadki przypadek. I nawet jego wystąpienie nic takiego złego nie robi, bo nawet jakby tam był bug, to na 99% zostanie złapany przez następny test.
Sytuacja identyczna jak z metodami diagnostycznymi. Identyczna, bo kod diagnostyczny i tak stosujesz - są częścią testów. To jest tylko kwestia organizacji kodu, semantycznie niczym się nie różni.
No to ponawiam pytanie, czemu nie przenieść tej funkcji do testów? Bo jeśli odpowiedź brzmi "dlatego żeby się dostać do prywatnych pól", to to nie jest semantycznie to samo. Żeby to było to samo, to taka metoda diagnostyczna musiałaby czytać tylko i wyłącznie publiczne pola i metody, i tylko te które są faktyczną częścią publicznego interfejsu żeby to było semantycznie to samo. Jeśli tak jest w istocie to nie mam problemu z takimi funkcjami. Jeśli faktycznie dotykają tylko i wyłącznie publicznych części interfejsu (które tak samo można by łatwo przetestować z testów jak tymi metodami diagnostycznymi), to zwracam honor - i takie funkcje jednak są okej. Wcześniej pomyślałem że te funkcje diagnostyczne dlatego są w kodzie produkcyjnym, żeby czytać pola prywatne i dlatego uznałem że są złe. Tylko jeśli tak jest to nadal nie rozumiem po co trzymać te funkcje przy kodzie, zamiast w testach.
Tak przy okazji, nigdy nie widziałem, aby TDD faktycznie powodowało lepszą jakość kodu, natomiast widziałem wielokrotnie jak prowadziło właśnie do patalogicznie złych designów i przesadnie skomplikowanego kodu najeżonego ifami.
To nie widziałeś nigdy TDD.
Z tego co mówisz, widziałeś jedynie projekty w który autor twierdził że praktykował TDD, podczas gdy to nie było to (tylko albo nie do końca to umiał, albo zrobił jakąś swoją fantazję, albo coś jeszcze innego).
Jeśli chcesz zobaczyć dobry przykład, to mogę pokazać swój projekt: https://github.com/t-regx/crlf Możesz przejrzeć historię powstawania, albo popatrzeć całościowo na origin/master
na efekt końcowy.
Bo zmusza programistę do myślenia o kodzie przez pryzmat przypadków, a nie ogólnego rozwiązania problemu.
No, i to się trochę mija z prawdę, bo w TDD właśnie o to chodzi żeby dotrzeć do ogólnego rozwiązania problemu, takiego który jest general/generic i pasuje do wielu przypadków. Jak powstaje Ci kod najeżony if
ami to właśnie nie jest generic, tylko specific, i to nie jest TDD. To jakaś smutna wizja.
Jeśli widziałeś takie przypadki w swojej karierze, to to nie było TDD.
RemoveAll
rzuci mi wyjątkiem jak nie znajdziex => x.IndexName == indexName
, ale widocznie byo to złe założenie