Jestem dość nowy w TDD i mam problemy z tworzeniem pierwszego testu, który pojawia się przed jakimkolwiek kodem implementacyjnym. Bez żadnych ram do kodu implementacyjnego mogę napisać mój pierwszy test, jakkolwiek chcę, ale zawsze wydaje się, że jest on skażony moim sposobem myślenia o problemie w Javie / OO.
Na przykład w moim Github ConwaysGameOfLifePrzykład pierwszy test, który napisałem (rule1_zeroNeighbours) Zacząłem od stworzenia obiektu GameOfLife, który nie został jeszcze zaimplementowany; nazywał metodę set, która nie istniała, metodę step, która nie istniała, metodę get, która nie istniała, a następnie użyła asert.
Testy ewoluowały, gdy napisałem więcej testów i zostały przebudowane, ale początkowo wyglądało to mniej więcej tak:
@Test
public void rule1_zeroNeighbours()
{
GameOfLife gameOfLife = new GameOfLife();
gameOfLife.set(1, 1, true);
gameOfLife.step();
assertEquals(false, gameOfLife.get(1, 1));
}
To wydawało mi się dziwne, kiedy wymuszałem projektowanie implementacji w oparciu o to, jak postanowiłem na tym wczesnym etapie napisać pierwszy test.
W jaki sposób rozumiesz TDD, czy to w porządku? Wydaje mi się, że przestrzegam zasad TDD / XP, ponieważ moje testy i implementacja ewoluowały wraz z refaktoryzacją, więc jeśli ten początkowy projekt okazałby się bezużyteczny, byłby otwarty na zmiany, ale wydaje mi się, że wymuszam kierunek na rozwiązanie, zaczynając w ten sposób.
Jak jeszcze ludzie używają TDD? Mógłbym przejść przez kolejne iteracje refaktoryzacji, zaczynając od braku obiektu GameOfLife, tylko prymitywów i metod statycznych, ale wydaje się to zbyt wymyślone.
źródło
Odpowiedzi:
Myślę, że to jest kluczowy punkt w twoim pytaniu, czy jest to pożądane, zależy od tego, czy skłaniasz się ku pomysłowi codeninji, że powinieneś zaprojektować z góry, a następnie użyć TDD do wypełnienia implementacji, czy pomysł Durrona, że testy powinny być zaangażowane w realizacja projektu oraz jego wdrożenia.
Myślę, że który z nich wolisz (lub gdzie wpadasz w środek), musisz odkryć coś dla siebie. Warto zrozumieć zalety i wady każdego podejścia. Prawdopodobnie jest ich dużo, ale powiedziałbym, że głównymi są:
Pro Upfront Design
Profesjonalny projekt jazdy testowej
Budując implementację wokół klienta kodu (twoich testów), otrzymujesz zgodność YAGNI prawie za darmo, o ile nie zaczniesz pisać niepotrzebnych przypadków testowych. Mówiąc bardziej ogólnie, otrzymujesz interfejs API zaprojektowany z myślą o jego użyciu przez konsumenta, co jest ostatecznie tym, czego chcesz.
Pomysł, aby narysować kilka diagramów UML przed napisaniem kodu, a następnie po prostu uzupełnieniem luk, jest przyjemny, ale rzadko realistyczny. W Code Complete Steve'a McConnella projekt jest znany jako „niegodziwy problem” - problem, którego nie można w pełni zrozumieć bez przynajmniej częściowego jego rozwiązania. Połącz to z faktem, że sam problem może ulec zmianie w wyniku zmieniających się wymagań, a ten model projektowania zaczyna być nieco beznadziejny. Jazda próbna pozwala po prostu odgryźć jeden kawałek pracy na raz - w projektowaniu, a nie tylko we wdrażaniu - i wiedzieć, że przynajmniej przez czas życia zmieniający kolor z czerwonego na zielony, to zadanie będzie nadal aktualne i istotne.
Jeśli chodzi o twój konkretny przykład, jak mówi durron, jeśli zdecydowałeś się na wyeliminowanie projektu, pisząc najprostszy test, wykorzystując minimalny interfejs, jaki można, prawdopodobnie zacząłbyś od prostszego interfejsu niż ten we fragmencie kodu .
źródło
Aby napisać test w pierwszej kolejności, musisz zaprojektować interfejs API , który następnie zamierzasz wdrożyć. Już zacząłeś niewłaściwą stopę, pisząc test, aby utworzyć cały
GameOfLife
obiekt i używając go do wdrożenia testu.Z praktycznych testów jednostkowych z JUnit i Mockito :
W teście niewiele próbujesz zaprojektować interfejs API. Utworzyłeś stanowy system, w którym cała funkcjonalność zawarta jest w
GameOfLife
klasie zewnętrznej .Gdybym miał napisać tę aplikację, pomyślałbym o elementach, które chcę zbudować. Na przykład, mógłbym stworzyć
Cell
klasę, napisać do tego testy, zanim przejdę do większej aplikacji. Z pewnością stworzyłbym klasę dla struktury danych „nieskończonej w każdym kierunku”, która jest wymagana do poprawnego wdrożenia Conwaya i przetestowania tego. Gdy to wszystko zostało zrobione, pomyślałem o napisaniu ogólnej klasy, która mamain
metodę i tak dalej.Łatwo jest przeszlifować krok „napisz test, który się nie powiedzie”. Ale napisanie nieudanego testu, który działa tak, jak chcesz, jest rdzeniem TDD.
źródło
boolean
, ten projekt z pewnością byłby gorszy pod względem wydajności. Chyba że w przyszłości będzie musiał zostać rozszerzony na inne automaty komórkowe z więcej niż dwoma stanami?Istnieje inna szkoła myślenia na ten temat.
Niektórzy mówią: test nie kompiluje się to błąd - idź napisz najmniejszy dostępny kod produkcyjny.
Niektórzy mówią: dobrze jest napisać test najpierw sprawdzić, czy jest do bani (czy nie), a następnie utworzyć brakujące klasy / metody
Przy pierwszym podejściu jesteś naprawdę w cyklu refrakcji czerwono-zielonej. Z sekundą masz nieco szerszy przegląd tego, co chcesz osiągnąć.
Od Ciebie zależy wybór sposobu pracy. Oba podejścia IMHO są prawidłowe.
źródło
Nawet kiedy wdrażam coś w sposób „zhakuj to razem”, wciąż wymyślam zajęcia i kroki, które będą zaangażowane w cały program. Więc przemyślałeś to i zapisałeś te przemyślenia projektowe jako test - to świetnie!
Teraz powtarzaj obie implementacje, aby wykonać ten wstępny test, a następnie dodaj więcej testów, aby ulepszyć i rozszerzyć projekt.
Pomocne może być użycie Ogórka lub podobnego narzędzia do napisania testów.
źródło
Zanim zaczniesz pisać testy, powinieneś pomyśleć o tym, jak zaprojektować swój system. Powinieneś poświęcić sporo czasu na etapie projektowania. Jeśli to zrobisz, nie poczujesz zamieszania w stosunku do TDD.
TDD jest tylko linkiem do programowania : TDD
1. Dodaj test
2. Uruchom wszystkie testy i sprawdź, czy nowy się nie powiedzie
3. Napisz kod
4. Uruchom testy
5. Kod refaktora
6. Powtórz
TDD pomaga objąć wszystkie wymagane funkcje, które zaplanowałeś przed rozpoczęciem tworzenia oprogramowania. link: Korzyści
źródło
Z tego powodu nie lubię testów na poziomie systemu napisanych w języku Java lub C #. Spójrz na SpecFlow dla c # lub jednego z frameworków testowych opartych na Cucumber dla java (może JBehave). Wtedy twoje testy mogą wyglądać mniej więcej tak.
I możesz zmienić projekt obiektu bez konieczności zmiany wszystkich testów systemu.
(„Normalne” testy jednostkowe są świetne podczas testowania pojedynczych klas).
Jakie są różnice między frameworkami BDD dla Java?
źródło