W przeciwieństwie do innych odpowiedzi, należy zauważyć, że niektóre sposoby testowania mogą stać się kruche, gdy testowany system (SUT) zostanie zrefaktoryzowany, jeśli test jest whitebox.
Jeśli korzystam z frameworka, który weryfikuje kolejność metod wywoływanych w próbkach (gdy kolejność jest nieistotna, ponieważ wywołania są wolne od efektów ubocznych); wtedy jeśli mój kod jest czystszy z tymi wywołaniami metod w innej kolejności, a ja dokonam refaktoryzacji, mój test się zepsuje. Ogólnie, makiety mogą wprowadzać kruchość do testów.
Jeśli sprawdzam wewnętrzny stan mojego SUT, ujawniając jego prywatnych lub chronionych członków (moglibyśmy użyć „przyjaciela” w Visual Basic lub eskalować poziom dostępu „wewnętrzny” i użyć „internalsvisibleto” w języku c #; w wielu językach OO, w tym c # mogłaby zostać użyta „ podklasa specyficzna dla testu ”), wtedy nagle stan wewnętrzny klasy będzie miał znaczenie - być może refaktoryzujesz klasę jako czarną skrzynkę, ale testy białej skrzynki zakończą się niepowodzeniem. Załóżmy, że jedno pole jest ponownie używane do oznaczania różnych rzeczy (nie jest to dobra praktyka!), Gdy stan SUT zmienia się - jeśli podzielimy je na dwa pola, może być konieczne przepisanie zepsutych testów.
Podklasy specyficzne dla testu można również wykorzystać do testowania metod chronionych - co może oznaczać, że refaktor z punktu widzenia kodu produkcyjnego jest przełomową zmianą z punktu widzenia kodu testowego. Przeniesienie kilku linii do lub z chronionej metody może nie wywoływać efektów ubocznych, ale przerwać test.
Jeśli użyję „ haków testowych ” lub jakiegokolwiek innego kodu kompilacyjnego specyficznego dla testu lub warunkowego, może być trudno zapewnić, że testy nie zostaną przerwane z powodu delikatnych zależności od wewnętrznej logiki.
Aby zapobiec sprzężeniu testów z intymnymi wewnętrznymi szczegółami SUT, pomocne może być:
- W miarę możliwości używaj kodów pośredniczących zamiast próbnych. Aby uzyskać więcej informacji, zobacz blog Fabio Periera na temat testów tautologicznych oraz mój blog na temat testów tautologicznych .
- Jeśli korzystasz z prób, unikaj sprawdzania kolejności wywoływanych metod, chyba że jest to ważne.
- Staraj się unikać sprawdzania wewnętrznego stanu SUT - w miarę możliwości używaj zewnętrznego API.
- Staraj się unikać logiki specyficznej dla testu w kodzie produkcyjnym
- Staraj się unikać używania podklas specyficznych dla testu.
Wszystkie powyższe punkty są przykładami sprzężenia białych skrzynek zastosowanych w testach. Aby całkowicie uniknąć refaktoryzacji testów niszczenia, należy zastosować testowanie SUT w czarnej skrzynce.
Zastrzeżenie: W celu omówienia refaktoryzacji używam tego słowa nieco szerzej, aby uwzględnić zmianę implementacji wewnętrznej bez widocznych efektów zewnętrznych. Niektórzy puryści mogą się nie zgadzać i odnoszą się wyłącznie do książki Martina Fowlera i Kenta Becka Refaktoryzacja - która opisuje operacje refaktoryzacji atomowej.
W praktyce staramy się podejmować nieco większe niełamliwe kroki niż opisane tam operacje atomowe, aw szczególności zmiany, które powodują, że kod produkcyjny zachowuje się identycznie z zewnątrz, mogą nie pozostawić pozytywnych wyników testów. Ale myślę, że sprawiedliwym jest włączenie „algorytmu zastępczego do innego algorytmu, który ma identyczne zachowanie” jako refaktora, i myślę, że Fowler się z tym zgadza. Sam Martin Fowler mówi, że refaktoryzacja może przerwać testy:
Kiedy piszesz test mockist, testujesz połączenia wychodzące z SUT, aby upewnić się, że poprawnie rozmawia z dostawcami. Klasyczny test dba tylko o stan końcowy - nie o to, jak ten stan został uzyskany. Testy próbne są zatem bardziej powiązane z wdrożeniem metody. Zmiana charakteru połączeń do współpracowników zwykle powoduje przerwanie testu kpiny.
[...]
Sprzężenie z implementacją przeszkadza również w refaktoryzacji, ponieważ zmiany w implementacji znacznie częściej psują testy niż w przypadku testów klasycznych.
Fowler - Kpiny nie są stubami