Kiedy piszesz "prawdziwy" kod w TDD?

johnny 08/19/2017. 11 answers, 20.464 views
tdd

Wszystkie przykłady, które przeczytałem i które widziałem na szkoleniowych filmach, mają uproszczone przykłady. Ale nie wiem, jak zrobić "prawdziwy" kod po tym, jak się zazieleniam. Czy to jest część "Refaktora"?

Jeśli mam dość złożony obiekt złożoną metodą, a ja piszę swój test i minimum, aby go przepuścić (po pierwszym niepowodzeniu, czerwony). Kiedy wrócę i napiszę prawdziwy kod? A ile prawdziwego kodu piszę przed ponownym testem? Zgaduję, że ostatnia to więcej intuicji.

Edit: Dziękuję wszystkim, którzy odpowiedzieli. Wszystkie twoje odpowiedzi pomogły mi niezmiernie. Wydaje się, że istnieją różne pomysły na temat tego, o co pytałem lub co mnie myliło, a może jest, ale to, o co prosiłem, to: mam wniosek o budowę szkoły.

W moim projekcie mam architekturę, od której chcę zacząć, Historie użytkowników, i tak dalej. Stąd biorę te Historie użytkowników i tworzę test, aby przetestować historię użytkownika. Użytkownik mówi, że ludzie zapisują się do szkoły i płacą opłaty rejestracyjne. Tak więc myślę o sposobie, by to zawiodło. Robiąc to, projektuję klasę testową dla klasy X (może Student), która się nie powiedzie. Następnie tworzę klasę "Student". Może "Szkoła" nie wiem.

Ale w każdym razie TD Design zmusza mnie do przemyślenia całej historii. Jeśli mogę sprawić, by test się nie powiódł, wiem, dlaczego to się nie udaje, ale to zakłada, że ​​mogę go przekazać. Chodzi o projektowanie.

Porównuję to do myślenia o rekursji. Rekursja nie jest trudną koncepcją. To może być trudniejsze do śledzenia tego w twojej głowie, ale w rzeczywistości najtrudniejszą częścią jest wiedza, kiedy rekursja "pęka", kiedy przestać (oczywiście moja opinia). Więc muszę pomyśleć o tym, co się zatrzymuje najpierw rekursja. Jest to tylko niedoskonała analogia i zakłada, że ​​każda iteracja rekurencyjna jest "przepustką". Ponownie, tylko opinia.

W realizacji Szkoła jest trudniejsza do zobaczenia. Księgi numeryczne i bankowe są "łatwe" w tym sensie, że można korzystać z prostej arytmetyki. Widzę a + b i zwracam 0 itd. W przypadku systemu ludzi, muszę się bardziej zastanowić, jak to implement . Mam pojęcie niepowodzenia, passa, refaktora (głównie z powodu studiów i tego pytania).

To, czego nie wiem, jest oparte na braku doświadczenia, moim zdaniem. Nie wiem, jak nie zapisać się do nowego ucznia. Nie wiem, jak zawodzić kogoś, kto wpisał nazwisko i został zapisany w bazie danych. Wiem, jak zrobić + 1 dla prostej matematyki, ale z podmiotami takimi jak osoba, nie wiem, czy testuję tylko, czy otrzymam unikalny identyfikator bazy danych lub coś innego, gdy ktoś wpisuje nazwę w baza danych lub oba lub żadne z nich.

A może to pokazuje, że nadal jestem zdezorientowany.

5 Comments
187 hobbs 07/25/2017
Po tym, jak ludzie z TDD wracają do domu na noc.
14 Goyo 07/25/2017
Jak myślisz, dlaczego napisany przez Ciebie kod nie jest prawdziwy?
2 johnny 07/26/2017
@RubberDuck Więcej niż inne odpowiedzi. Jestem pewien, że wkrótce się do tego odezwę. To wciąż jest trochę obce, ale nie zamierzam się poddawać. To, co powiedziałeś, miało sens. Staram się, aby miało to sens w moim kontekście lub zwykłej aplikacji biznesowej. Może system inwentaryzacji lub podobne. Muszę to rozważyć. Jestem wdzięczny za poświęcony czas. Dzięki.
1 Edmund Reed 07/26/2017
Odpowiedzi już trafiły w sedno, ale tak długo, jak wszystkie testy mijają, i nie potrzebujesz nowych testów / funkcjonalności, można założyć, że kod, który masz, jest skończony, pręty linting.
3 Borjab 07/26/2017
W pytaniu pojawia się asumpt, który może być problematyczny w "Mam dość złożony obiekt złożoną metodą". W TDD najpierw piszesz swoje testy, więc zaczynasz od dość prostego kodu. To zmusi cię do zakodowania przyjaznej dla testu struktury, która będzie musiała być modułowa. Tak złożone zachowanie będzie tworzone przez połączenie prostszych obiektów. Jeśli skończysz z dość złożonym obiektem lub metodą, to wtedy, gdy będziesz refaktoryzować

11 Answers


RubberDuck 07/27/2017.

Jeśli mam dość złożony obiekt złożoną metodą, a ja piszę swój test i minimum, aby go przepuścić (po pierwszym niepowodzeniu, czerwony). Kiedy wrócę i napiszę prawdziwy kod? A ile prawdziwego kodu piszę przed ponownym testem? Zgaduję, że ostatnia to więcej intuicji.

Nie "wracasz" i piszesz "prawdziwy kod". To wszystko prawdziwy kod. To, co robisz, to wrócić i dodać kolejny test, który forces cię do change kodu w celu przejścia testu.

A ile kodu piszesz przed ponownym testem? Żaden. Piszemy zero kodu bez testu błędu, który forces do napisania więcej kodu.

Zwróć uwagę na wzór?

Przejdźmy przez (inny) prosty przykład w nadziei, że pomoże.

 Assert.Equal("1", FizzBuzz(1)); 

Łatwy peazy.

 public String FizzBuzz(int n) {
    return 1.ToString();
} 

Nie to, co nazwałbyś prawdziwym kodem, prawda? Dodajmy test, który wymusza zmianę.

 Assert.Equal("2", FizzBuzz(2)); 

Moglibyśmy zrobić coś głupiego, jak if n == 1 , ale przejdziemy do rozsądnego rozwiązania.

 public String FizzBuzz(int n) {
    return n.ToString();
} 

Chłodny. Będzie to działać dla wszystkich numerów innych niż FizzBuzz. Jakie są następne dane wejściowe, które wymuszą zmianę kodu produkcyjnego?

 Assert.Equal("Fizz", FizzBuzz(3));

public String FizzBuzz(int n) {
    if (n == 3)
        return "Fizz";
    return n.ToString();
} 

I jeszcze raz. Napisz test, który jeszcze nie przejdzie.

 Assert.Equal("Fizz", FizzBuzz(6));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    return n.ToString();
} 

A teraz pokryliśmy wszystkie wielokrotności trzech (które nie są również wielokrotnościami pięciu, zauważymy je i wrócimy).

Jeszcze nie napisaliśmy testu dla "Buzza", więc napiszmy to.

 Assert.Equal("Buzz", FizzBuzz(5));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n == 5)
        return "Buzz"
    return n.ToString();
} 

I znowu wiemy, że jest inny przypadek, który musimy rozwiązać.

 Assert.Equal("Buzz", FizzBuzz(10));

public String FizzBuzz(int n) {
    if (n % 3 == 0)
        return "Fizz";
    if (n % 5 == 0)
        return "Buzz"
    return n.ToString();
} 

A teraz możemy obsłużyć wszystkie wielokrotności 5, które nie są również wielokrotnościami 3.

Do tej pory ignorowaliśmy etap refaktoryzacji, ale widzę pewne powielanie. Oczyśćmy to teraz.

 private bool isDivisibleBy(int divisor, int input) {
    return (input % divisor == 0);
}

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Chłodny. Teraz usunęliśmy duplikację i stworzyliśmy dobrze nazwaną funkcję. Jaki następny test możemy napisać, który zmusi nas do zmiany kodu? Cóż, unikaliśmy przypadku, w którym liczba jest podzielna przez 3 i 5. Napiszmy to teraz.

 Assert.Equal("FizzBuzz", FizzBuzz(15));

public String FizzBuzz(int n) {
    if (isDivisibleBy(3, n) && isDivisibleBy(5, n))
        return "FizzBuzz";
    if (isDivisibleBy(3, n))
        return "Fizz";
    if (isDivisibleBy(5, n))
        return "Buzz"
    return n.ToString();
} 

Testy mijają, ale mamy więcej duplikacji. Mamy opcje, ale zamierzam zastosować "Wyodrębnij zmienną lokalną" kilka razy, abyśmy refaktoryzowali zamiast przepisywania.

 public String FizzBuzz(int n) {

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

I uwzględniliśmy każdy rozsądny wkład, ale co z unreasonable wkładem? Co się stanie, jeśli przejdziemy 0 lub ujemny? Napisz te przypadki testowe.

 public String FizzBuzz(int n) {

    if (n < 1)
        throw new InvalidArgException("n must be >= 1);

    var isDivisibleBy3 = isDivisibleBy(3, n);
    var isDivisibleBy5 = isDivisibleBy(5, n);

    if ( isDivisibleBy3 && isDivisibleBy5 )
        return "FizzBuzz";
    if ( isDivisibleBy3 )
        return "Fizz";
    if ( isDivisibleBy5 )
        return "Buzz"
    return n.ToString();
} 

Czy to już wygląda jak "prawdziwy kod"? Co ważniejsze, w którym momencie przestała być "nierealnym kodem" i przejściem do bycia "prawdziwym"? To jest coś do przemyślenia ...

Mogłem to zrobić po prostu szukając testu, który, jak wiedziałem, nie przejdzie na każdym kroku, ale miałem dużo praktyki. Kiedy jestem w pracy, rzeczy nigdy nie są takie proste i nie zawsze wiem, jaki test wymusi zmianę. Czasami napiszę test i zaskoczę, że już go mija! Zdecydowanie zalecamy, aby przed rozpoczęciem rozpocząć tworzenie "Listy testowej". Ta lista testów powinna zawierać wszystkie "interesujące" dane wejściowe, które możesz wymyślić. Możesz nie używać ich wszystkich i prawdopodobnie dodasz przypadki, ale ta lista służy jako mapa drogowa. Moja lista testowa dla FizzBuzz wyglądałaby tak.

  • Negatywny
  • Zero
  • Jeden
  • Dwa
  • Trzy
  • Cztery
  • Pięć
  • Sześć (nietrywialna wielokrotność 3)
  • Dziewięć (3 do kwadratu)
  • Dziesięć (nietrywialna wielokrotność 5)
  • 15 (wielokrotność 3 i 5)
  • 30 (nietrywialna wielokrotność 3 i 5)
5 comments
3 maple_shaft♦ 07/27/2017
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona na czat .
40 GManNickG 07/27/2017
Chyba że całkowicie nie rozumiem tej odpowiedzi: "Możemy zrobić coś głupiego, jak gdyby n == 1, ale przejdziemy do rozsądnego rozwiązania". - całość była głupia. Jeśli wiesz z góry, potrzebujesz funkcji <spec>, napisz testy dla <spec> i pomiń część, w której piszesz wersje, które oczywiście zawodzą <spec>. Jeśli znajdziesz błąd w <spec>, to na pewno: napisz test najpierw, aby sprawdzić, czy możesz go wykonać przed naprawieniem i obserwuj testowe testy po naprawie. Ale nie ma potrzeby udawać tych wszystkich pośrednich kroków.
15 user3791372 07/28/2017
Komentarze wskazujące główne wady tej odpowiedzi i ogólnie TDD zostały przeniesione na czat. Jeśli rozważasz użycie TDD, przeczytaj "czat". Niestety komentarze "jakości" są teraz ukryte pośród wielu gadżetów, z którymi przyszli uczniowie mogą się zapoznać.
nbro 07/28/2017
Byłbym bardziej precyzyjny w odniesieniu do zawartości tej "listy testowej", jeśli chciałbyś poprawić tę odpowiedź. Powiedziałbym wprost o "wartościach granicznych" i "partycjonowaniu klas".
2 hvd 07/30/2017
@GManNickG Uważam, że chodzi o to, aby uzyskać odpowiednią liczbę testów. Wcześniejsze wcześniejsze testowanie ułatwia pominięcie tego, co należy przetestować w specjalnych przypadkach, prowadząc albo do sytuacji, które nie są odpowiednio uwzględnione w testach, albo do zasadniczo tej samej sytuacji, która jest niepotrzebnie pokryta wieloma czasami w testach. Jeśli możesz to zrobić bez tych pośrednich kroków, świetnie! Jednak nie wszyscy mogą to zrobić, ale to jest coś, co wymaga praktyki.

GenericJon 07/24/2017.

"Prawdziwy" kod to kod, który piszesz, aby przejść test. Really . To takie proste.

Kiedy ludzie mówią o pisaniu absolutnego minimum, aby test był zielony, oznacza to tylko, że twój prawdziwy kod powinien być zgodny z zasadą YAGNI .

Pomysł na krok refaktora jest po prostu oczyścić to, co napisałeś, gdy jesteś szczęśliwy, że spełnia wymagania.

Tak długo, jak testy, które piszesz, obejmują twoje wymagania dotyczące produktu, po ich przejściu kod jest kompletny. Pomyśl o tym, jeśli wszystkie wymagania biznesowe będą miały test, a wszystkie testy będą zielone, a co jeszcze można napisać? (Okej, w rzeczywistości nie mamy do czynienia z pełnym testowaniem, ale teoria jest dobra).

5 comments
44 Derek Elkins 07/24/2017
Testy jednostkowe nie mogą w rzeczywistości objąć twoich wymagań produktowych nawet dla względnie banalnych wymagań. W najlepszym przypadku próbkują przestrzeni wejścia-wyjścia, a pomysł polega na tym, że (poprawnie) generalizujesz do pełnej przestrzeni wejścia-wyjścia. Oczywiście twój kod może być tylko dużym switch z przypadkiem dla każdego testu jednostkowego, który przejdzie wszystkie testy i nie powiedzie się dla żadnych innych danych wejściowych.
8 Taemyr 07/25/2017
@DerekElkins TDD zleca awaryjne testy. Niezaliczone testy jednostkowe.
6 jonrsharpe 07/25/2017
@DerekElkins, dlatego nie piszesz tylko testów jednostkowych, a także dlatego, że istnieje ogólne założenie, że próbujesz stworzyć coś nie tylko podróbka!
35 Derek Elkins 07/25/2017
@jonrsharpe Zgodnie z tą logiką nigdy nie napisałbym trywialnych implementacji. Np. W przykładzie FizzBuzz w odpowiedzi RubberDucka (który wykorzystuje tylko testy jednostkowe), pierwsza implementacja wyraźnie "tylko podróbka". Moje zrozumienie tego pytania jest dokładnie tą dychotomią między pisaniem kodu, który, jak wiesz, jest niekompletny, a kodem, który naprawdę wierzysz, zaimplementuje wymóg "prawdziwego kodu". Moja "wielka switch " miała być logiczną skrajnością "pisania minimum, aby testy były zielone". Uważam, że pytanie OP brzmi: gdzie w TDD jest zasada, która unika tej dużej switch ?
2 Luaan 07/25/2017
@GenericJon To trochę zbyt optymistyczne z mojego doświadczenia :) Po pierwsze, są ludzie, którzy lubią bezmyślną, powtarzalną pracę. Będą szczęśliwsi dzięki gigantycznej zmianie zdań niż "skomplikowanemu procesowi decyzyjnemu". A żeby stracić pracę, albo będą potrzebować kogoś, kto ich wyśle ​​na technikę (i będą mieli lepsze dowody, że faktycznie traci możliwości / pieniądze firmy!), Albo wyjątkowo źle. Po przejęciu konserwacji wielu takich projektów mogę stwierdzić, że kod bardzo naiwny jest łatwy do utrzymania przez dziesięciolecia, o ile sprawi, że klient będzie zadowolony (i zapłacił).

Carl Raymond 07/24/2017.

Krótka odpowiedź brzmi, że "prawdziwy kod" jest kodem, który sprawia, że ​​test przechodzi. Jeśli możesz sprawić, że test przejdzie z czymś innym niż prawdziwy kod, dodaj więcej testów!

Zgadzam się, że wiele tutoriali na temat TDD jest uproszczonych. To działa przeciwko nim. Zbyt prosty test dla metody, która, powiedzmy, oblicza 3 + 8 naprawdę nie ma wyboru, ale także obliczyć 3 + 8 i porównać wynik. Wygląda na to, że po prostu duplikujesz cały kod, a testowanie jest bezsensowną, podatną na błędy dodatkową pracą.

Kiedy jesteś dobry w testowaniu, to poinformujesz, w jaki sposób tworzysz swoją aplikację i jak piszesz swój kod. Jeśli masz kłopot z sensownymi, pomocnymi testami, prawdopodobnie powinieneś przemyśleć nieco swój projekt. Dobrze zaprojektowany system jest łatwy do przetestowania - co oznacza, że ​​rozsądne testy są łatwe do wymyślenia i wdrożenia.

Kiedy najpierw napiszesz swoje testy, obejrzysz je, a następnie napisz kod, który je przekazuje, jest to dyscyplina, która zapewnia, że ​​cały twój kod ma odpowiednie testy. Nie podporządkowuję się niewolniczo tej zasadzie, kiedy koduję; często piszę testy po fakcie. Ale najpierw wykonywanie testów pomaga zachować uczciwość. Z pewnym doświadczeniem zaczniesz zauważać, kiedy kodujesz siebie w kącie, nawet jeśli nie piszesz najpierw testów.

4 comments
6 Steve Jessop 07/26/2017
Osobiście test, który bym napisał był assertEqual(plus(3,8), 11) , a nie assertEqual(plus(3,8), my_test_implementation_of_addition(3,8)) . W przypadku bardziej złożonych przypadków zawsze poszukujesz sposobu na udowodnienie poprawności wyniku, other than dynamicznego obliczania poprawnego wyniku w teście i sprawdzenia równości.
Steve Jessop 07/26/2017
Tak więc dla naprawdę głupiego sposobu robienia tego dla tego przykładu, możesz udowodnić, że plus(3,8) zwrócił poprawny wynik przez odjęcie 3 od niego, odjęcie 8 od tego i sprawdzenie wyniku przed 0. To jest tak oczywiste odpowiednik assertEqual(plus(3,8), 3+8) jest nieco absurdalny, ale jeśli testowany kod buduje coś bardziej skomplikowanego niż zwykła liczba całkowita, to przyjmowanie wyniku i sprawdzanie poprawności każdej części jest często właściwe podejście. Alternatywnie, coś jak for (i=0, j=10; i < 10; ++i, ++j) assertEqual(plus(i, 10), j)
Steve Jessop 07/26/2017
... ponieważ pozwala to uniknąć wielkiego strachu, który polega na tym, że pisząc test, popełnimy ten sam błąd w temacie "jak dodać 10", który zrobiliśmy w kodzie na żywo. Zatem test ostrożnie unika pisania jakiegokolwiek kodu, który dodaje 10 do czegokolwiek, w teście, że plus() może dodać 10 do rzeczy. Wciąż oczywiście polegamy na sprawdzonych przez programistę wartościach pętli intialnych.
3 Warbo 07/28/2017
Po prostu chcę zaznaczyć, że nawet jeśli piszesz testy po fakcie, to nadal dobrze jest obserwować, jak zawodzą; znajdź jakąś część kodu, która wydaje ci się kluczowa dla tego, nad czym pracujesz, nieco ją podkręć (np. zamień a + na - lub, cokolwiek), uruchom testy i zobacz, jak się nie udają, cofnij zmianę i obserwuj, jak mijają. Wiele razy to robiłem, test nie zawodzi, czyni go gorszym niż bezużytecznym: nie tylko nie testuje niczego, ale daje mi fałszywą pewność, że coś jest testowane!

Victor Cejudo 07/25/2017.

Czasami niektóre przykłady dotyczące TDD mogą być mylące. Jak już wcześniej zauważyli inni, kod, który piszę, aby sprawdziły testy, jest rzeczywistym kodem.

Ale nie myśl, że prawdziwy kod wygląda jak magia - to źle. Potrzebujesz lepszego zrozumienia tego, co chcesz osiągnąć, a następnie musisz odpowiednio wybrać test, zaczynając od najłatwiejszych przypadków i narożnych przypadków.

Na przykład, jeśli chcesz napisać lexer, zacznij od pustego łańcucha, a następnie spacji białymi, następnie liczby, następnie liczby otoczonej białymi cyframi, następnie błędnej liczby itp. Te małe przekształcenia doprowadzą cię do prawy algorytm, ale nie przeskakujesz od najłatwiejszego przypadku do wysoce złożonego przypadku, który został wybrany głupio, aby uzyskać prawdziwy kod.

Bob Martin wyjaśnia to doskonale tutaj .


CandiedOrange 07/25/2017.

Część refaktora jest czyszczona, gdy jesteś zmęczony i chcesz wrócić do domu.

Kiedy masz zamiar dodać funkcję, częścią refaktora jest to, co zmieniłeś przed następnym testem. Zmieniasz kod, aby zrobić miejsce dla nowej funkcji. Robisz to, gdy know jaka będzie nowa funkcja. Nie, kiedy tylko to sobie wyobrażasz.

Może to być tak proste, jak zmiana nazwy GreetImpl na GreetWorld przed utworzeniem klasy GreetMom (po dodaniu testu), aby dodać funkcję, która wyświetli GreetMom "Hi Mom".


graeme 07/27/2017.

Ale prawdziwy kod pojawiłby się na etapie refaktora fazy TDD. Tzn. Kod, który powinien być częścią ostatecznej wersji.

Testy należy wykonywać za każdym razem, gdy wprowadzasz zmianę.

Motto cyklu życia TDD będzie: CZERWONY ZIELONY REFAKTOR

RED : Napisz testy

GREEN : Zrób uczciwą próbę uzyskania kodu funkcjonalnego, który przejdzie testy tak szybko, jak to możliwe: duplikat kodu, niejasno nazwane zmienne, hacki o najwyższym porządku itd.

REFACTOR : oczyść kod, poprawnie nazwij zmienne. DRY do góry kod.

5 comments
5 mcottle 07/25/2017
Wiem, co mówisz o fazie "zielonej", ale oznacza to, że wartości zwracane na twardym okablowaniu do wykonania testów mogą być odpowiednie. Z mojego doświadczenia wynika, że ​​"zielony" powinien być uczciwą próbą uczynienia działającego kodu, aby spełnić wymóg, może nie być idealny, ale powinien być tak kompletny i "możliwy do wysłania", jak programista może zarządzać w pierwszym przebiegu. Refaktoryzacja jest prawdopodobnie najlepiej zrobiona jakiś czas później po tym, jak zrobisz więcej rozwoju, a problemy z pierwszym przejściem staną się bardziej widoczne i pojawią się możliwości DRY.
graeme 07/25/2017
@mcottle uważam te wszystkie części tego samego zadania. załatw to, a potem posprzątaj. Dalsze refaktoryzacje powinny odbywać się w miarę upływu czasu jako część innych zadań.
1 Bryan Boettcher 07/25/2017
@mcottle: możesz być zaskoczony, jak wiele implementacji repozytorium tylko do pobrania może być wartościami zakodowanymi w bazie kodu. :)
6 Kaz 07/25/2017
Dlaczego miałabym kiedykolwiek napisać kod bzdury i oczyścić go, kiedy mogę wykręcić niezły kod jakości produkcji prawie tak szybko, jak mogę pisać? :)
1 Kaz 07/27/2017
@TimothyTruckle Co zrobić, jeśli zajmie 50 minut, aby znaleźć najprostszą możliwą zmianę, ale tylko 5, aby znaleźć drugą najprostszą możliwą zmianę? Czy idziemy z drugim najprostszym, czy szukamy najprostszych?

Timothy Truckle 07/27/2017.

Kiedy piszesz "prawdziwy" kod w TDD?

Faza red to miejsce, w którym write kod.

W fazie refactoring głównym celem jest delete kodu.

W fazie red robisz wszystko, aby test przebiegał as quick as possible i at any cost . Całkowicie lekceważycie to, co kiedykolwiek słyszeliście o dobrych praktykach kodowania lub wzorach projektowych. Sprawienie, by test był zielony, to wszystko, co ważne.

W fazie refactoring bałagan, który właśnie zrobiłeś. Teraz najpierw sprawdź, czy właśnie dokonana zmiana jest najwyższą na liście Priorytet transformacji, a jeśli istnieje jakakolwiek powielalność kodu, możesz ją usunąć najprawdopodobniej poprzez zastosowanie wzoru projektu.

Wreszcie poprawiasz czytelność, zmieniając nazwy identyfikatorów i wyodrębniając magic numbers i / lub ciągi literowe do stałych.


To nie jest czerwony refactor, to czerwony-zielony-refaktor. - Rob Kinyon

Dzięki za wskazanie tego.

Tak więc jest to green faza, w której piszesz real code

W fazie red zapisujesz executable specification ...

2 comments
Rob Kinyon 07/27/2017
To nie jest czerwony refactor, to czerwony-zielony-refaktor. "Czerwony" oznacza, że ​​zestaw testowy przechodzi z zielonego (wszystkie testy przechodzą) na czerwony (jeden test kończy się niepowodzeniem). "Zielony" to miejsce, w którym niezadowalająco bierzesz zestaw do testów od czerwonego (jeden test kończy się niepowodzeniem) do zielonego (wszystkie testy przechodzą). "Refaktor" to miejsce, w którym bierzesz swój kod i czynisz go ładnym, zachowując wszystkie testy.
Timothy Truckle 07/27/2017
@RobKinyon Dzięki, zaktualizował odpowiedź.

Robert Andrzejuk 07/27/2017.

Real Code cały czas piszesz Real Code .

Na każdym kroku piszesz kod, aby spełnić warunki, które Twój Kod spełni dla przyszłych dzwoniących Twojego kodu (którym możesz być Ty lub nie ...).

Myślisz, że nie piszesz przydatnego ( real ) kodu, ponieważ za chwilę możesz go zrestrukturyzować.

Code-Refactoring to proces przebudowy istniejącego kodu komputerowego - zmiana faktoringu - bez zmiany jego zachowania zewnętrznego.

Oznacza to, że chociaż zmieniasz kod, warunki, które zasygnalizował kod, pozostają niezmienione. A kontrole ( tests ) Zaimplementowane w celu weryfikacji Twojego kodu już istnieją, aby sprawdzić, czy Twoje modyfikacje niczego nie zmieniły. Więc kod, który napisałeś przez cały czas, jest tam, tylko w inny sposób.

Innym powodem, dla którego możesz myśleć, że to nie jest prawdziwy kod, jest to, że robisz przykłady, w których program końcowy może już być przez Ciebie przewidziany. Jest to bardzo dobre, ponieważ pokazuje, że masz wiedzę na temat domain w której programujesz.
Ale wiele razy programiści znajdują się w domain która jest new , unknown im. Nie wiedzą, jaki będzie wynik końcowy, a TDD to technique pisania krok po kroku programów, dokumentująca naszą knowledge temat działania tego systemu i weryfikowania, czy nasz kod działa w ten sposób.

Kiedy czytałem książkę (*) na temat TDD, dla mnie najważniejszą cechą, która wyróżniała się była lista: TODO. Okazało się, że TDD to także technika, która pomaga programistom skupić się na jednej rzeczy naraz. Jest to również odpowiedź na Twoje pytanie na temat How much Real code to write ? Powiedziałbym wystarczająco dużo kodu, aby skupić się na jednej rzeczy na raz.

(*) "Test Driven Development: By Example" autorstwa Kent Beck

1 comments
2 Robert Andrzejuk 07/27/2017
"Test Driven Development: By Example" autorstwa Kent Beck

Zenilogix 07/31/2017.

Nie piszesz kodu, aby testy zakończyły się niepowodzeniem.

Piszesz testy, aby określić, jaki sukces powinien wyglądać, co powinno początkowo się nie udać, ponieważ jeszcze nie napisałeś kodu, który przejdzie.

Cały problem związany z pisaniem testów początkowo nieudanych to wykonanie dwóch rzeczy:

  1. Obejmują wszystkie przypadki - wszystkie przypadki nominalne, wszystkie skrzynie brzegowe itp.
  2. Zatwierdź swoje testy. Jeśli widzisz je tylko raz, to czy możesz mieć pewność, że niezawodnie zgłaszają awarię, gdy się pojawi?

Punktem, za którym kryje się czerwony-zielony-refaktor jest to, że pisanie poprawnych testów najpierw daje pewność, że kod, który napisałeś, aby zaliczyć testy, jest poprawny i pozwala na refaktoryzację z przekonaniem, że twoje testy poinformują cię tak szybko, jak to tylko możliwe. coś się psuje, więc możesz natychmiast wrócić i naprawić.

W moim własnym doświadczeniu (C # / .NET), czysty test-pierwszy jest trochę nieosiągalnym ideałem, ponieważ nie można skompilować połączenia do metody, która jeszcze nie istnieje. Tak więc "testowanie pierwszego" polega na zakodowaniu w pierwszej kolejności interfejsów i implementacji stubb, a następnie zapisaniu testów na elementach pośredniczących (które początkowo się nie powiodą), dopóki kody pośrednie nie zostaną poprawione. Nigdy nie piszę "kodu błędu", tylko budując z kodów pośredniczących.


Zan Lynx 07/27/2017.

Myślę, że możesz być zdezorientowany między testami jednostkowymi i testami integracyjnymi. Sądzę, że mogą być również testy akceptacyjne, ale to zależy od twojego procesu.

Gdy przetestujesz wszystkie małe "jednostki", przetestujesz je wszystkie połączone lub "zintegrowane". Zwykle jest to cały program lub biblioteka.

W kodzie, który napisałem, integracja testuje bibliotekę z różnymi programami testowymi, które odczytują dane i przekazują je do biblioteki, a następnie sprawdzają wyniki. Potem robię to z wątkami. Następnie robię to za pomocą wątków i fork () w środku. Następnie uruchamiam go i zabijam -9 po 2 sekundach, a następnie uruchamiam go i sprawdzam jego tryb przywracania. Stłukłem to. Torturuję go na różne sposoby.

Wszystko to jest również testowanie, ale nie mam ładny czerwony / zielony wyświetlacz dla wyników. Albo się uda, albo przekopię się przez kilka tysięcy linii kodu błędu, aby dowiedzieć się dlaczego.

Tam testujesz "prawdziwy kod".

Pomyślałem o tym, ale może nie wiesz, kiedy masz pisać testy jednostkowe. Skończyłeś pisać testy jednostkowe, gdy twoje testy wykonują wszystko, co wskazałeś, i powinieneś zrobić. Czasami możesz stracić kontrolę nad tym pośród wszystkich błędów i skrajnych przypadków, więc możesz chcieć zrobić fajną grupę testową szczęśliwych testów ścieżek, które po prostu przejdą od razu do specyfikacji.

1 comments
Peter Mortensen 07/27/2017
(jego = zaborczy, jest = "jest" lub "ma". Zobacz na przykład, How to Use Its and It's .)

user3791372 07/27/2017.

W odpowiedzi na tytuł pytania: "Kiedy piszesz" prawdziwy "kod w TDD?", Odpowiedź brzmi: "rzadko" lub "bardzo wolno".

Brzmisz jak student, więc odpowiem, jakby doradzał studentowi.

Będziesz się uczyć wielu kodowania "teorii" i "technik". Doskonale nadają się do spędzania czasu na przecenionych kursach studenckich, ale z bardzo niewielką korzyścią dla ciebie, której nie można było przeczytać w książce w połowie czasu.

Zadaniem programisty jest wyłącznie tworzenie kodu. Kod, który działa naprawdę dobrze. Dlatego programista koduje kod w swoim umyśle, na papierze, w odpowiedniej aplikacji itp. I planujesz omijać potencjalne błędy / dziury z wyprzedzeniem, logicznie i logicznie myśląc przed kodowaniem.

Ale musisz wiedzieć, jak złamać aplikację, aby móc zaprojektować przyzwoity kod. Na przykład, gdybyś nie wiedział o Little Bobby Table (xkcd 327), prawdopodobnie nie udałoby ci się odświeżyć twoich danych wejściowych przed rozpoczęciem pracy z bazą danych, więc nie byłbyś w stanie zabezpieczyć danych wokół tej koncepcji.

TDD to po prostu przepływ pracy zaprojektowany w celu zminimalizowania błędów w kodzie poprzez tworzenie testów na to, co może pójść źle, zanim zakodujesz aplikację, ponieważ kodowanie może być trudne wykładniczo, im więcej kodu wprowadzisz, a ty zapomnisz o błędach, o których myślałeś. Kiedy myślisz, że skończyłeś swoją aplikację, uruchamiasz testy i boom, miejmy nadzieję, że błędy zostaną złapane w twoich testach.

TDD nie jest - jak niektórzy uważają - napisać test, przekazać go z minimalnym kodem, napisać kolejny test, zdobyć to przejście z minimalnym kodem, itp. Zamiast tego jest to sposób na pomoc w bezpiecznym kodowaniu. Ten ideał ciągłego kodowania refaktoryzującego, który działa z testami, jest idiotyczny, ale jest to fajna koncepcja dla studentów, ponieważ sprawia, że ​​czują się wspaniale, gdy dodają nową funkcję i nadal uczą się kodować ...

Nie upuść tej pułapki i nie dostrzegaj swojej roli kodowania tego, co to jest - zadaniem kodera jest wyłącznie wytwarzanie kodu. Kod, który działa naprawdę dobrze. Teraz pamiętaj, że będziesz na zegarze jako profesjonalny programista, a twój klient nie będzie dbał o to, czy napiszesz 100 000 twierdzeń, czy 0. Po prostu chcą kodu, który działa. Naprawdę dobrze.

5 comments
3 johnny 07/25/2017
Nie jestem nawet blisko studenta, ale czytam i staram się stosować dobre techniki i być profesjonalistą. W tym sensie jestem "studentem". Po prostu zadaję podstawowe pytania, bo tak właśnie jestem. Chciałbym dokładnie wiedzieć, dlaczego robię to, co robię. Sedno sprawy. Jeśli tego nie rozumiem, nie podoba mi się to i zaczynam zadawać pytania. Muszę wiedzieć dlaczego, jeśli zamierzam go użyć. TDD wydaje się intuicyjnie dobry pod pewnymi względami, jak wiedza o tym, co trzeba stworzyć i przemyśleć, ale implementacja była trudna do zrozumienia. Myślę, że teraz mam lepsze pojęcie.
4 Sean Burton 07/27/2017
Takie są zasady TDD. Możesz napisać kod w dowolny sposób, ale jeśli nie zastosujesz się do tych trzech zasad, nie robisz TDD.
2 user3791372 07/27/2017
"Zasady" jednej osoby? TDD jest sugestią, aby pomóc ci kodować, a nie religię. To smutne, że tak wielu ludzi stosuje ideę tak anally. Nawet pochodzenie TDD jest kontrowersyjne.
2 Alex 07/28/2017
@ user3791372 TDD to bardzo surowy i jasno określony proces. Nawet jeśli wielu uważa, że ​​jest to po prostu "wykonuj testowanie podczas programowania", to nie jest. Spróbujmy tu nie mieszać terminów, to pytanie dotyczy procesu TDD, a nie ogólnego testowania.

Related questions

Hot questions

Language

Popular Tags