Najlepsze praktyki dotyczące modernizacji starszego kodu za pomocą testów automatycznych

22

Mam zamiar ponownie zaimplementować już zdefiniowany interfejs (zestaw plików nagłówkowych C ++) w stosunkowo dużej i starej bazie kodu. Zanim to zrobię, chciałbym mieć możliwie pełny zakres testów, aby móc wykryć błędy ponownej implementacji tak wcześnie i łatwo, jak to możliwe. Problem polega na tym, że już istniejąca baza kodu nie została zaprojektowana w taki sposób, aby można ją było łatwo przetestować, z (bardzo) dużymi klasami i funkcjami, wysokim stopniem sprzężenia, funkcjami z (wieloma) skutkami ubocznymi itp.

Byłoby miło usłyszeć o wszelkich wcześniejszych doświadczeniach z podobnymi zadaniami oraz kilka dobrych i konkretnych wskazówek na temat tego, jak poszedłeś na temat modernizacji automatycznych testów (jednostki, integracji, regresji itp.) W swoim starszym kodzie.

tjansson
źródło
1
Krok 1: Wyszukaj przepełnienie stosu. Pytanie zostało zadane. Wiele, wiele razy.
S.Lott

Odpowiedzi:

20

Przede wszystkim przeczytaj i przeczytaj Efektywna praca ze starszym kodem autorstwa Michaela Feathersa - jest to niezbędna pomoc przy takich zadaniach.

Następnie kilka notatek:

  • czy masz dokładną specyfikację / umowę dotyczącą interfejsu, czy praktycznie masz tylko istniejącą implementację jako „specyfikację”? W pierwszym przypadku łatwiej jest wykonać kompletne przepisanie od zera, w drugim przypadku jest to niemożliwe.
  • jeśli chcesz ponownie wdrożyć interfejs, najbardziej przydatnym sposobem na wykorzystanie zasobów testowych jest napisanie testów tylko na interfejsie. Oczywiście nie kwalifikuje się to do testów jednostkowych w ścisłym tego słowa znaczeniu, a raczej testów funkcjonalnych / akceptacyjnych, ale nie jestem purystą :-) Jednak testy te są wielokrotnego użytku i umożliwiają bezpośrednie porównanie wyników z dwóch implementacji obok siebie .
  • ogólnie wolałbym przefaktoryzować istniejący kod niż przepisać od zera, chyba że jest to całkowicie niemożliwe do utrzymania. (Ale w tym przypadku, jak zamierzasz napisać testy jednostkowe przeciwko niemu?) Sprawdź ten post od Joela, aby uzyskać bardziej szczegółową dyskusję na ten temat. Utworzenie zestawu testów akceptacyjnych dla interfejsu daje cienką, ale przydatną siatkę bezpieczeństwa, dzięki której możesz zacząć ostrożnie przebudowywać istniejący kod, aby umożliwić jego testowanie jednostkowe (korzystając z pomysłów z książki Feathers).
Péter Török
źródło
Dałbym to +3, gdybym mógł. WELC to niezbędna lektura i zdecydowanie refaktoryzacja ...
Johnsyweb
Jeden drobny komentarz do drugiego punktu jest taki, że w przypadku starszych systemów testy powinny być wykonywane zgodnie z nastawieniem testu charakterystyki . Oznacza to, że wiernie rejestruj bieżące zachowanie oprogramowania i powstrzymaj się od zmiany tego zachowania, nawet jeśli niektóre wyniki testu wydają się dziwne lub niezgodne z umysłem dotyczącym testowania jednostkowego. (Przy okazji ten pomysł pochodzi również od autora WELC.)
rwong
@ rwong, rzeczywiście. Bez szczegółowej specyfikacji lub kompetentnego właściciela produktu deweloper nie może zdecydować, czy określone zachowanie programu a) jest zamierzone i wymagane, b) było niezamierzone, ale do tej pory użytkownicy są od niego zależni, c) błąd, który faktycznie szkodzi użytkownikom, d) błąd całkowicie niezauważony do tej pory. W pierwszych dwóch przypadkach „naprawienie” faktycznie zaszkodziłoby użytkownikom, aw ostatnim przypadku poprawka - choć teoretycznie poprawna - nie zapewni widocznych korzyści.
Péter Török
4

Najlepszą znaną metodą jest metoda Mikado. http://mikadomethod.wordpress.com/2010/08/04/the-mikado-method-book/ To tylko uogólnienie prostej techniki, ale to jedyny sposób, w jaki wiem, jak zacząć poprawiać jakość kodu w dużej bazie kodu bez niepotrzebnego ryzyka.

WEWLC jest również bardzo dobrą książką na ten temat, ale pisanie w C ++ nie zawsze jest przydatne w kodzie Java lub Ruby.

Uberto
źródło
2

Testy dopasowania retro na starej podstawie kodu mogą być dość trudne, jeśli mają monolityczny wygląd.

Jeśli to możliwe (czy masz czas / pieniądze), jednym ze sposobów na przejście do przodu byłoby przefakturowanie kodu na bardziej testowalne jednostki.

ozz
źródło
1

Chciałbym dodać jeden link . Istnieje kilka przykładów niezbyt łatwych do przetestowania implementacji, które zostały ponownie uwzględnione w kodzie bardziej przyjaznym dla xUnit. Jeśli chodzi o ogólne podejście, spróbuj wypróbować wspomniane już linki (post Joela, Praca ze starszym kodem

yoosiba
źródło