Testowanie kodu ogólnie nie jest łatwe. Gdyby tak było, robilibyśmy to już dawno temu i nie robilibyśmy tego w ciągu ostatnich 10-15 lat. Jedną z największych trudności zawsze było określenie, w jaki sposób przetestować kod, który został napisany w sposób spójny, dobrze przemyślany i możliwy do przetestowania bez przerywania enkapsulacji. Dyrektor BDD sugeruje, że skupiamy się prawie całkowicie na zachowaniu, i pod pewnymi względami wydaje się sugerować, że tak naprawdę nie musisz tak bardzo martwić się wewnętrznymi szczegółami, ale często może to utrudnić sprawdzenie, czy istnieją wiele prywatnych metod, które robią „rzeczy” w bardzo ukryty sposób, ponieważ może to zwiększyć ogólną złożoność testu, aby poradzić sobie ze wszystkimi możliwymi wynikami na poziomie bardziej publicznym.
Kpiny mogą w pewnym stopniu pomóc, ale znowu są dość zewnętrznie skoncentrowane. Wstrzykiwanie zależności może również działać całkiem nieźle, ponownie z próbami lub podwójnymi testami, ale może to również wymagać ujawnienia elementów za pośrednictwem interfejsu lub bezpośrednio, że w innym przypadku wolałbyś pozostać ukryty - jest to szczególnie prawdziwe, jeśli chcesz mieć niezły poziom bezpieczeństwa paranoicznego na temat niektórych klas w twoim systemie.
Dla mnie jury wciąż nie zastanawia się, czy zaprojektować twoje klasy, aby były łatwiejsze do przetestowania. Może to powodować problemy, jeśli okaże się, że musisz dostarczyć nowe testy przy zachowaniu starszego kodu. Zgadzam się, że powinieneś być w stanie przetestować absolutnie wszystko w systemie, ale nie podoba mi się pomysł ujawnienia - nawet pośrednio - prywatnych elementów wewnętrznych klasy, tylko po to, aby napisać dla nich test.
Dla mnie rozwiązaniem zawsze było przyjęcie dość pragmatycznego podejścia i połączenie szeregu technik w celu dopasowania do konkretnej sytuacji. Używam wielu odziedziczonych podwójnych testów, aby ujawnić wewnętrzne właściwości i zachowania dla moich testów. Kpię ze wszystkiego, co można dołączyć do moich klas, a tam, gdzie nie zagrozi to bezpieczeństwu moich klas, zapewnię środki do nadpisania lub wstrzyknięcia zachowań do celów testowania. Rozważę nawet udostępnienie interfejsu bardziej opartego na zdarzeniach, jeśli pomoże to poprawić zdolność do testowania kodu
Tam, gdzie znajduję jakiś „niestabilny” kod, szukam, czy mogę refaktoryzować, aby uczynić rzeczy bardziej testowalnymi. Tam, gdzie masz dużo prywatnego kodu, który ukrywa się za kulisami, często znajdziesz nowe klasy, które czekają na przełamanie. Klasy te mogą być używane wewnętrznie, ale często można je testować niezależnie, zachowując mniej prywatnych zachowań, a następnie często mniej warstw dostępu i złożoności. Jedną rzeczą, której staram się unikać, jest jednak pisanie kodu produkcyjnego z wbudowanym kodem testowym. Może być kuszące tworzenie „ końcówek testowych ”, które skutkują takimi okropnościami if testing then ...
, które wskazują na problem z testowaniem, który nie został w pełni zdekonstruowany i nie został w pełni rozwiązany.
Pomocne może okazać się przeczytanie książki xUnit Test Patterns Gerarda Meszarosa , która omawia wszystkie tego rodzaju rzeczy bardziej szczegółowo niż ja. Prawdopodobnie nie robię wszystkiego, co on sugeruje, ale pomaga wyjaśnić niektóre trudniejsze sytuacje testowe. Na koniec dnia chcesz być w stanie spełnić wymagania dotyczące testowania, jednocześnie stosując preferowane projekty, i pomaga to lepiej zrozumieć wszystkie opcje, aby lepiej zdecydować, gdzie możesz pójść na kompromis.