TL; DR
Pisanie dobrych, przydatnych testów jest trudne i wiąże się z wysokimi kosztami w C ++. Czy doświadczeni programiści mogą podzielić się uzasadnieniem na temat tego, co i kiedy testować?
Długa historia
Kiedyś zajmowałem się programowaniem opartym na testach, właściwie cały mój zespół, ale nie działało to dobrze dla nas. Mamy wiele testów, ale nigdy nie wydają się obejmować przypadków, w których mamy rzeczywiste błędy i regresje - które zwykle występują, gdy jednostki wchodzą w interakcje, a nie z powodu ich izolowanego zachowania.
Często jest to tak trudne do przetestowania na poziomie jednostki, że przestaliśmy robić TDD (z wyjątkiem komponentów, w których to naprawdę przyspiesza rozwój) i zamiast tego zainwestowaliśmy więcej czasu w zwiększenie zasięgu testu integracji. Podczas gdy testy małych jednostek nigdy nie wykryły żadnych prawdziwych błędów i były po prostu tylko kosztami utrzymania, testy integracyjne były naprawdę warte wysiłku.
Teraz odziedziczyłem nowy projekt i zastanawiam się, jak zacząć go testować. Jest to natywna aplikacja C ++ / OpenGL, więc testy integracyjne nie są tak naprawdę opcją. Ale testowanie jednostkowe w C ++ jest nieco trudniejsze niż w Javie (musisz jawnie tworzyć różne rzeczy virtual
), a program nie jest silnie zorientowany obiektowo, więc nie mogę wyśmiewać / usuwać niektórych rzeczy.
Nie chcę się rozrywać i OO-ize wszystko po prostu napisać kilka testów na potrzeby pisania testów. Więc pytam: do czego powinienem pisać testy? na przykład:
- Funkcje / klasy, które często się zmieniam?
- Funkcje / klasy, które trudniej przetestować ręcznie?
- Funkcje / klasy, które są już łatwe do przetestowania?
Zacząłem badać niektóre pełne szacunku podstawy kodu C ++, aby zobaczyć, jak przebiegają testy. W tej chwili szukam kodu źródłowego Chromium, ale trudno mi wyodrębnić z niego uzasadnienie testowania. Jeśli ktoś ma dobry przykład lub post na temat tego, jak podchodzą do tego popularni użytkownicy C ++ (faceci z komitetu, autorzy książek, Google, Facebook, Microsoft, ...), byłoby to bardzo pomocne.
Aktualizacja
Szukałem w tej witrynie i Internecie od momentu napisania tego. Znaleziono kilka dobrych rzeczy:
- Kiedy nie należy przeprowadzać testu jednostkowego?
- /programming/109432/what-not-to-test-when-it-come-to-unit-testing
- http://junit.sourceforge.net/doc/faq/faq.htm#best
Niestety, wszystkie z nich są raczej skoncentrowane na Javie / C #. Pisanie wielu testów w Javie / C # nie jest dużym problemem, więc korzyść zwykle przewyższa koszty.
Ale jak napisałem powyżej, w C ++ jest trudniej. Zwłaszcza, jeśli twoja baza kodu nie jest tak bardzo OO, musisz poważnie zepsuć wszystko, aby uzyskać dobry zasięg testu jednostkowego. Na przykład: odziedziczona aplikacja ma Graphics
przestrzeń nazw, która jest cienką warstwą powyżej OpenGL. W celu przetestowania któregokolwiek z podmiotów - które bezpośrednio korzystają z jego funkcji - musiałbym przekształcić to w interfejs i klasę i wstrzyknąć to we wszystkie byty. To tylko jeden przykład.
Odpowiadając na to pytanie, należy pamiętać, że muszę poczynić dość dużą inwestycję w pisanie testów.
źródło
Odpowiedzi:
Testowanie jednostkowe to tylko jedna część. Testy integracyjne pomagają rozwiązać problem Twojego zespołu. Testy integracyjne można pisać dla wszystkich rodzajów aplikacji, także dla aplikacji rodzimych i OpenGL. Powinieneś sprawdzić „Rosnące oprogramowanie obiektowe kierowane testami” Steve Freemann i Nat Pryce (np. Http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 ). Prowadzi Cię krok po kroku przez rozwój aplikacji z graficznym interfejsem użytkownika i komunikacją sieciową.
Testowanie oprogramowania, które nie było testowane, to inna historia. Sprawdź, czy Michael Feathers „Efektywnie współpracuje ze starszym kodem” (http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052).
źródło
Szkoda, że TDD „nie działało dobrze”. Myślę, że to jest klucz do zrozumienia, gdzie się zwrócić. Odwiedź ponownie i zrozum, jak TDD nie działało, co mogłeś zrobić lepiej, dlaczego były trudności.
Oczywiście twoje testy jednostkowe nie wykryły znalezionych błędów. Właśnie o to chodzi. :-) Nie znalazłeś tych błędów, ponieważ zapobiegłeś ich wystąpieniu, zastanawiając się, jak powinny działać interfejsy i jak się upewnić, że zostały odpowiednio przetestowane.
Aby odpowiedzieć, kwestionujesz, jak już stwierdziłeś, kod testowania jednostkowego, który nie jest przeznaczony do testowania, jest trudny. W przypadku istniejącego kodu bardziej efektywne może być użycie testowego środowiska funkcjonalnego lub integracyjnego niż testowego. Przetestuj system ogólnie, koncentrując się na określonych obszarach.
Oczywiście nowy rozwój będzie korzystał z TDD. W miarę dodawania nowych funkcji refaktoryzacja TDD może pomóc przetestować nowy rozwój, jednocześnie umożliwiając opracowanie nowego testu jednostkowego starszych funkcji.
źródło
Nie zrobiłem TDD w C ++, więc nie mogę tego komentować, ale powinieneś przetestować oczekiwane zachowanie twojego kodu. Chociaż implementacja może się zmienić, zachowanie powinno (zwykle?) Pozostać takie samo. W świecie zorientowanym na Java \ C # oznacza to, że testujesz tylko metody publiczne, piszesz testy pod kątem oczekiwanego zachowania i robisz to przed implementacją (co zwykle lepiej powiedzieć niż zrobić :)).
źródło