jmolinski / minesweeper

1 stars 0 forks source link

Testy jednostkowe: BoardField #8

Open MacDada opened 9 years ago

MacDada commented 9 years ago

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

  1. Tworzysz obiekt BoardField (obojętne czy z bombą czy bez)
  2. Sprawdzasz że na starcie is_marked() zwraca false
  3. Odpalasz mark()
  4. Sprawdzasz, że is_marked() zwraca true
  5. Odpalasz unmark()
  6. Sprawdzasz, że is_marked() zwraca false

Revealed BoardField cannot be marked

  1. Tworzysz obiekt BoardField, który nie jest bombą
  2. Odpalasz reveal() (czy tam show() czy jak tam nazwy w końcu :D)
  3. Odpalasz mark()
  4. Sprawdzasz, że wybucha błędem

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 :)

jmolinski commented 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 ( ͡° ͜ʖ ͡°)

MacDada commented 9 years ago

@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 :)

jmolinski commented 9 years ago

@MacDada dobra, poczytałem trochę, do testów będę używał narzędzi z biblioteki Boost, zaufam znanej marce :)

MacDada commented 9 years ago

@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 :)).

MacDada commented 9 years ago

@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