Open MacDada opened 9 years ago
@MacDada jak to ma byc rozwiązane tak zupełnie czysto technicznie? To ma byc zwykła klasa która wywołuje metody i porównuje to co zwracają? To ma być wbudowane w już istniejącą klasę? Co jeśli jakaś funkcja jest void i nic nie zwraca? Czy mechanizm testów mam mieć wbudowany w IDE? Chyba muszę w ogóle poczytać czym są testy jednostkowe ( ͡° ͜ʖ ͡°)
@Glenpl Google'uj, poczytaj trochę teorii na temat TDD. Poszukaj przykładów bibliotek, które mają napisane testy.
Technicznie dla ccp
ciężko mi cokolwiek powiedzieć (google mi pokazuje np framework CppUnit
– ale czy jest spoko, czy jest popularny – nie wiem – choć Martin Fowler wśród twórców brzmi obiecująco :)).
Idea ogólna jest taka, że do każdej klasy, którą chcesz napisać, najpierw piszesz oddzielną klasę ją testującą.
W kodzie testującym sprawdzasz czy klasa testowana działa jak jak chcesz.
Np, chcesz, żeby była taka klasa jak BoardField
. Piszesz więc test, który sprawdza, że można utworzyć jej obiekt. I tyle.
Dalej, chciałbyś, żeby BoardField
można było „oznaczyć” i „odznaczyć”. W teście więc „projektujesz” sobie jak chcesz korzystać z tej klasy. Możesz np napisać, że po wywołaniu metody mark()
, metoda is_marked()
powinna zwrócić true
. I bierzesz się za implementację w klasie BoardField
.
Potem możesz chcieć, żeby klasa BoardField
robiła X. Piszesz więc test, który sprawdza, że BoardField
to robi. Potem piszesz implementację tak, żeby test przechodził.
Zapętlasz.
Pewne rzeczy trudno przetestować (jak klasa robi za dużo, jak niejawnie korzysta z innych obiektów – np sam je sobie tworzy, jak robi efekty uboczne typu drukowanie na ekran; przede wszystkim jak robi „za dużo”, itp) – rzeczy, które trudno testować pokazują, gdzie jest błąd w dizajnie.
Różnie bywa u mnie z testowaniem (na co dzień pracuję z archaicznym kodem, który jest ekstramalnie trudny do testowania), ale ostatnio siadłem do małego projektu, gdzie wszystko robię TDD.
Możesz zobaczyć moje „specyfikacje” tutaj: https://github.com/MacDada/WykopAspieStats/tree/master/spec
Ale najlepiej znajdź przykłady w CPP :)
@MacDada dobra, poczytałem trochę, do testów będę używał narzędzi z biblioteki Boost, zaufam znanej marce :)
@Glenpl Ogólnie wygląda spoko. Rzuciła mi się w oczy też zabawka Google'a (używana m.in. do testowania Chome'a):
https://code.google.com/p/googletest/wiki/Primer
O tyle ciekawa, że integruje się z fw do mockowania (tworzenia obiektów „bez pisania klas”, tylko na potrzeby testów):
https://code.google.com/p/googlemock/
Z tego co widzę, boost
żadnej opcji mockowania nie posiada. O ile nie jest to jakoś niezbędne, o tyle znacznie ułatwia TDD w niektórych przypadkach (np chcesz testować zapisywanie Boarda, a… jeszcze nie napisałeś samego Boarda :)).
@Glenpl Ale widzę, że można googlemocka używać z dowolnym innym frameworkiem testującym, więc w sumie co Tobie wygodniej wygląda :) https://code.google.com/p/googlemock/wiki/ForDummies#Using_Google_Mock_with_Any_Testing_Framework
Kod się rozrasta i komplikuje, co raz więcej czasu spada na debugging i ręczne przechodzenie gry.
Co robią programiści jak problem się powtarza? Automatyzują! :)
I choć automatyzacja to jedno, nauka to drugie – TDD (test driven development) moim zdaniem jest podstawowym narzędziem prowadzącym do wysokiej jakości kodu, bo sprawia, że zaczynasz więcej myśleć o kompetencjach obiektów i o tym jak w ogóle sprawić, żeby były testowalne (a nieprzypadkowo kod testowalny posiada cechy kodu wysokiej jakości).
Jak nie bawiłeś się tym jeszcze, zacznij przy pisaniu BoardField'a.
Testy powinny sprawdzać zachowanie obiektu, więc przykładowy scenariusz:
BoardField can be marked and unmarked
BoardField
(obojętne czy z bombą czy bez)is_marked()
zwracafalse
mark()
is_marked()
zwracatrue
unmark()
is_marked()
zwracafalse
Revealed BoardField cannot be marked
BoardField
, który nie jest bombąreveal()
(czy tamshow()
czy jak tam nazwy w końcu :D)mark()
j.w. dla
unmark()
itp wszystko co ten obiekt robi
Testy mają opisywać zachowanie. Czego się po tym obiekcie spodziewać? Jak go używać? Żywa dokumentacja :)