Po co przeprowadzać testy jednostkowe na serwerze CI?

98

Dlaczego miałbyś uruchamiać testy jednostkowe na serwerze CI?

Z pewnością, zanim coś zostanie zobowiązane do opanowania, programista przeprowadził już wszystkie testy jednostkowe i naprawił wszelkie błędy, które mogły wystąpić w ich nowym kodzie. Czy nie o to chodzi w testach jednostkowych? W przeciwnym razie właśnie popełnił uszkodzony kod.

Steve
źródło
51
Nasi programiści nie mogą zobowiązać się do opanowania. Pchają do gałęzi funkcji, a następnie serwer CI łączy się z master i uruchamia testy. Jeśli im się uda, wtedy zmiany są scalane do opanowania. Tak więc kod z uszkodzonymi testami nie może być nadrzędny ...
Boris the Spider
2
@ BoristheSpider - naprawdę bardzo dobry przepływ pracy. masterpowinien być zawsze rozsądny i najlepiej automatycznie wdrażany przy każdym połączeniu w środowisku pomostowym w celu wewnętrznej kontroli jakości i testowania.
Per Lundberg
130
„Z pewnością, zanim coś zostanie zobowiązane do opanowania, programista przeprowadził już wszystkie testy jednostkowe i naprawił wszelkie błędy, które mogły wystąpić w ich nowym kodzie”. W jakim świecie fantasy żyjesz?
jpmc26
5
W niektórych branżach ważną częścią nie jest tylko przeprowadzanie testów na kodzie, ale także przeprowadzanie testów na plikach binarnych . Uruchomienie testów na wyjściu CI oznacza, że ​​możesz zagwarantować, że dostarczony produkt działa, ponieważ dokładny plik binarny otrzymany przez klienta to ten, który przeszedł wszystkie testy. Brzmi to trywialnie, ale czasem może to mieć wpływ (jeden z nich widziałem zaciemnianie; przy skomplikowanych projektach lub przy dziwnej konfiguracji może powodować problemy z zaciemnioną wersją, której nie było w czystej wersji).
anaximander
5
„Z pewnością, zanim coś zobowiązuje się do opanowania, programista przeprowadził już wszystkie testy jednostkowe i naprawił wszelkie błędy, które mogły wystąpić w ich nowym kodzie.” ... nie jestem pewien, czy to poważne
chucksmash

Odpowiedzi:

223

Z pewnością, zanim coś zostanie zobowiązane do opanowania, programista przeprowadził już wszystkie testy jednostkowe i naprawił wszelkie błędy, które mogły wystąpić w ich nowym kodzie.

Albo nie. Może być wiele przyczyn, dla których tak się dzieje:

  • Deweloper nie ma dyscypliny, aby to zrobić
  • Oni zapomnieli
  • Nie popełnili wszystkiego i wcisnęli niekompletny zestaw zatwierdzeń (dzięki Matthieu M.
  • Przeprowadzili tylko niektóre testy, ale nie cały pakiet (dzięki nhgrif )
  • Testowali w swoim oddziale przed połączeniem (dzięki nhgrif * 2)

Ale prawdziwym celem jest uruchomienie testów na komputerze, który nie jest maszyną programistyczną. Ten, który jest skonfigurowany inaczej.

Pomaga to wychwycić problemy, w których testy i / lub kod zależą od czegoś specyficznego dla pudełka programisty (konfiguracja, dane, strefa czasowa, ustawienia regionalne, cokolwiek innego).

Inne ważne powody, dla których kompilacje CI uruchamiają testy:

  • Testowanie na różnych platformach innych niż główne platformy programistyczne, co może być trudne dla programisty. (dzięki TZHX )
  • Akceptacja / integracja / end-to-end / Naprawdę długo działające testy mogą być uruchomione na serwerze CI, który zwykle nie byłby uruchamiany na komputerze dewelopera. (dzięki Ixrec )
  • Deweloper może wprowadzić niewielką zmianę przed wypchnięciem / zatwierdzeniem (myśląc, że jest to bezpieczna zmiana i dlatego nie uruchamia testów). (dzięki Ixrec * 2)
  • Konfiguracja serwera CI zwykle nie obejmuje wszystkich narzędzi programistycznych i konfiguracji, dlatego jest bliższa systemowi produkcyjnemu
  • Systemy CI budują projekt od początku za każdym razem, co oznacza, że ​​kompilacje są powtarzalne
  • Zmiana biblioteki może powodować problemy na dalszych etapach - serwer CI można skonfigurować do budowania wszystkich zależnych baz kodu, nie tylko biblioteki
Oded
źródło
36
Inne typowe przyczyny: 1) Serwer CI może przeprowadzać testy integracji / akceptacji na wysokim poziomie, które deweloperzy zawsze je uruchamiają zbyt długo. 2) Deweloper uruchomił je, a następnie dokonał jednej drobnej zmiany, zanim był przekonany, że są pewni, że niczego nie zepsuje, ale chcemy być pewni.
Ixrec
11
Zmiana zależności często uruchamia także wszystkie kolejne kompilacje. Jeśli zmiana dokonana przez programistę psuje coś w dół, nie jest łatwo zauważyć podczas modyfikowania biblioteki (np. Zmiana bazowego typu danych z SortedSet na HashSet (tylko pod warunkiem umowy z Setem)), a ktoś w dalszej kolejności pracował nad błędnym założeniem, że Zestaw został posortowany). Brak uruchamiania (dalszych) testów na serwerze CI pozwoliłby na jakiś czas na zaostrzenie się błędu.
2
@MichaelT Good catch. To właściwie jest przyczyną> 90% naszych awarii CI, nie wiem, jak to zapomniałem ...
Ixrec
34
Ponadto uruchomienie ich w środowisku CI zwykle oznacza, że ​​konfigurujesz projekt od zera , zapewniając, że kompilacja jest powtarzalna .
mgarciaisaia
5
Można również zatwierdzić dwie zmiany, które testowały się osobno, ale zostały rozdzielone (np. Jedna usuwa nieużywany interfejs API, a druga zaczyna go używać).
Simon Richter
74

Jako programista, który nie przeprowadza wszystkich testów integracji i testów jednostkowych przed zatwierdzeniem kontroli źródła, zaoferuję tutaj swoją obronę.

Musiałbym zbudować, przetestować i sprawdzić, czy aplikacja działa poprawnie na:

  • Microsoft Windows XP i Vista z kompilatorem Visual Studio 2008.
  • Microsoft Windows 7 z kompilatorem Visual Studio 2010.
    • Aha, i MSI buduje dla każdego z nich.
  • RHEL 5 i 6 z odpowiednio 4.1 i 4.4 (podobnie CentOS)
    • 7 wkrótce. Woop-de-woop.
  • Stacja robocza Fedory z GCC dla ostatnich trzech ostatnich wersji.
  • Debian (i pochodne takie jak Ubuntu) dla ostatnich trzech ostatnich wersji.
  • Mac OSX w ostatnich trzech ostatnich wersjach.
    • I pakiety (rpm, dmg itp.)

Dodaj Fortran (zarówno z kompilatorami Intela, jak i GNU), Python (i różne wersje w zależności od systemu operacyjnego) oraz komponenty skryptu bash / bat i myślę, że widać spiralne zmiany

A więc to szesnaście maszyn, które musiałbym mieć, żeby przeprowadzić kilka testów kilka razy dziennie. Zarządzanie infrastrukturą byłoby prawie pełnym etatem. Myślę, że prawie każdy zgodziłby się z tym, że jest to nierozsądne, zwłaszcza pomnożenie go przez liczbę osób w projekcie. Dlatego pozwalamy naszym serwerom CI wykonać pracę.

Testy jednostkowe nie zatrzymują Państwo popełnienia złamany kod, oni powiedzieć, czy oni wiedzą, złamałeś coś. Ludzie mogą powiedzieć „testy jednostkowe powinny być szybkie” i mówić o zasadach, wzorcach projektowych i metodach, ale w rzeczywistości czasem lepiej jest pozwolić komputerom, które zaprojektowaliśmy do powtarzalnych, monotonnych zadań, wykonywać te zadania i angażować się tylko wtedy, gdy powiedz nam, że coś znaleźli.

TZHX
źródło
3
Jednostka testy testowania kodu nie konfiguracje. Byłoby naprawdę obojętne, gdybyś dodał nowy test i rzucił go na ścianę, nie uruchamiając go najpierw lokalnie ...
Robbie Dee
33
@RobbieDee Obawiam się, że nie rozumiem, o co ci chodzi? Nie sugeruję, tworząc nowe testy bez testując je lokalnie, lub po prostu ślepo popełnienia rzeczy do kontroli źródła bez testując je sam, a ja by uruchomić testy na własnym komputerze - ale „konfiguracja” nie muszą być badane na zachowanie spójnego , i lepiej to zrobić stosunkowo szybko, gdy umysł programisty wciąż jest w tym obszarze, niż znaleźć problem, gdy zespół, który głównie używa komputerów Mac, obudzi się o cztery tysiące mil i zaktualizuje swoje kopie.
TZHX
7
@RobbieDee Powiedziałbym, że TZHX uruchomiłby wszystkie testy lokalnie, gdyby mogły, ale nie mogą . Ponieważ TZHX nie może tego zrobić, uruchamiają niektóre testy lokalnie (te, które mogą być uruchomione w ich systemie deweloperskim i na przykład wystarczająco krótkie lub najbardziej odpowiednie dla zmienionego kodu) i pozwalają na pełne naładowanie baterii w systemie CI. Dość rozsądne.
muru
11
@RobbieDee: Wierzy w testy jednostkowe. Więc testuje je na swoim MacBooku Air, przekazuje i melduje się. Serwery CI z Red Hat, Solaris i Windows następnie uruchamiają te testy ponownie. Czy nie jest miło wiedzieć, że to, co przetestowałeś, działa również na platformach produkcyjnych?
slebetman
2
@RobbieDee: Często pisałem testy jednostkowe, które były specyficzne dla określonego kompilatora na pewnej platformie. Rozważ np. Podsystem graficzny, który korzysta z instrukcji procesora AMD (konkurenta Intel), które są dostępne tylko w wersji g ++ (kompilator GNU C ++) w wersji 4.5 lub nowszej, ale zdarza się, że pracuję na procesorze Atom i ICC (Intel C ++ Kompilator). Bezsensowne byłoby uruchamianie testów AMD / g ++ 4.5 za każdym razem na tej maszynie, ale kod jest testowany przed wydaniem; a mój własny niezależny od procesora kod musi zostać przetestowany pod kątem właściwej interoperacyjności. Jasne, są maszyny wirtualne i emulatory, ...
fresnel
23

Oprócz doskonałej odpowiedzi Oded:

  • Testujesz kod z repozytorium . Może działać na twoim komputerze z twoimi plikami ... których zapomniałeś zatwierdzić. Może zależeć od nowej tabeli, która nie ma skryptu tworzenia (na przykład w Liquibase), niektórych danych konfiguracyjnych lub plików właściwości.
  • Unikasz problemów z integracją kodu. Jeden programista pobiera ostatnią wersję, tworzy test jednostkowy i integracyjny, dodaje kod, przechodzi wszystkie testy na swoim komputerze, zatwierdza i wypycha. Inny programista właśnie to zrobił. Obie zmiany są same w sobie, ale ich scalenie powoduje błąd. Może to być połączenie repozytorium lub po prostu to, że nie zostanie wykryty jako konflikt. Np. Dev 1 usuwa plik, który w ogóle nie był używany. Kody Dev 2 dla tego pliku i testy bez zmian Dev 1.
  • Opracowujesz skrypt do automatycznego wdrożenia z repozytorium. Posiadanie uniwersalnego skryptu budowania i wdrażania rozwiązuje wiele problemów. Niektórzy deweloperzy mogli dodać opcję lib lub kompilacji, która nie jest wspólna dla wszystkich. Nie tylko oszczędza to czas, ale co ważniejsze, sprawia, że ​​wdrożenie jest bezpieczne i przewidywalne. Ponadto możesz wrócić do repozytorium do wersji 2.3.1 i wdrożyć tę wersję ze skryptem, który działa z tą wersją. Obejmuje obiekty bazy danych, takie jak widoki, procedury składowane, widoki i wyzwalacze, które powinny być wersjonowane. (Lub nie będziesz mógł wrócić do wykonalnej wersji).
  • Inne testy : jak testy integracyjne, wydajnościowe i kompleksowe. Może to być powolne i może obejmować narzędzia do testowania, takie jak Selenium. Możesz potrzebować pełnego zestawu danych z prawdziwą bazą danych zamiast próbnych obiektów lub HSQL.

Kiedyś pracowałem w firmie, która miała wiele błędów podczas wdrażania z powodu procesu łączenia i wdrażania. Było to spowodowane dziwnym, zastrzeżonym szkieletem, który utrudniał testowanie i CI. Nie było przyjemnym doświadczeniem, że kod, który działał doskonale przy programowaniu, nie dotarł bezpośrednio do produkcji.

Borjab
źródło
Tak, po prostu zapominanie o dokonaniu niektórych zmian jest bardzo powszechne. Powiedziałbym, że zapomnienie o dodaniu „svn” nowych plików, a więc zapomnienie ich późniejszego zatwierdzenia jest najpopularniejszym sposobem na uzyskanie nieudanej automatycznej kompilacji.
sharptooth
22

Można by pomyśleć, że nie, ale programiści są ludźmi i czasami zapominają.

Ponadto programiści często nie pobierają najnowszego kodu. Ich ostatnie testy mogą działać poprawnie, a następnie w momencie odprawy ktoś inny dokonuje przełomowej zmiany.

Twoje testy mogą również opierać się na lokalnym (niezaznaczonym) zasobie. Coś, czego nie wykryłyby testy lokalnych jednostek.

Jeśli uważasz, że wszystko powyższe jest fantazyjne, istnieje poziom powyżej CI (przynajmniej w TFS) o nazwie Gated, gdzie kompilacje, które nie przeszły pomyślnie testów, są odkładane na półkę i nie są przypisywane do bazy kodu.

Robbie Dee
źródło
7
Widziałem więcej ups, zapomniałem się zgodzić, że awarie CI, do których chcę się przyznać.
Dan Neely
@ DanNeely Aby być uczciwym, bije kopnięcie tyłka przez kierownika budowy, ponieważ zapomniałeś powiedzieć mu / jej o czymś ... :-)
Robbie Dee
3
To jeden z powodów, dla których kocham CI. Znalezienie i naprawa własnych ooopses jest znacznie lepsze niż znalezienie kogoś dla Ciebie.
Dan Neely
14

zanim coś się zobowiązuje do opanowania

Zazwyczaj konfiguruję CI, aby uruchamiał się przy każdym zatwierdzeniu. Gałęzie nie łączą się w master, dopóki gałąź nie zostanie przetestowana. Jeśli polegasz na przeprowadzaniu testów na systemie głównym, otwiera się okno, w którym kompilacja może zostać uszkodzona.

Przeprowadzenie testów na komputerze CI dotyczy powtarzalnych wyników. Ponieważ serwer CI ma znane czyste środowisko pobrane z VCS, wiesz, że wyniki testu są poprawne. Podczas uruchamiania lokalnego możesz zapomnieć o zatwierdzeniu kodu potrzebnego do przekazania lub mieć niezatwierdzony kod, który powoduje, że przechodzą, gdy powinny zawieść.

Może także zaoszczędzić czas programistów, uruchamiając równolegle różne pakiety, szczególnie jeśli niektóre są powolnymi, wielominutowymi testami, które prawdopodobnie nie będą uruchamiane lokalnie po każdej zmianie.

W mojej obecnej pracy nasze wdrożenie produkcyjne jest testowane, gdy CI przejdzie wszystkie testy. Skrypty wdrażania zapobiegną wdrożeniu, chyba że zostaną przekazane. Uniemożliwia to przypadkowe zapomnienie ich uruchomienia.

CI będące częścią przepływu pracy odciąża również programistów. Czy jako programista zwykle przeprowadzasz linijkę, analizator statyczny, test jednostkowy, pokrycie kodu i test integracji dla każdej pojedynczej zmiany? CI może całkowicie automatycznie i bez konieczności myślenia o tym - zmniejszając zmęczenie decyzją.

Daenyth
źródło
1
Tak naprawdę nie powinieneś mieć powolnych testów jednostkowych - to narusza PIERWSZE zasady.
Robbie Dee
4
@RobbieDee: Myślę, że zwykle serwer CI uruchamia wszystkie testy, a nie tylko testy jednostkowe.
RemcoGerlich
4
@RobbieDee: teoretycznie wszystkie testy jednostkowe są szybkie. W praktyce ... Niezależnie od tego, CI może i powinien przeprowadzić wszystkie testy - kłaczki, analizy statyczne, testy jednostkowe, testy integracyjne.
Daenyth,
2
@RobbieDee Oczywiście specyfika konfiguracji będzie się różnić w zależności od zespołu. Nawet jeśli kompilacje trwają kilka minut, często można równolegle uruchomić wiele z nich. Biorąc pod uwagę jedną monolityczną bazę kodu, może to być większa wada, ale IME nie stanowi bariery.
Daenyth,
1
@RobbieDee Myślę, że to zależy bardziej od twojej architektury. Widziałem, jak to działa ręcznie dla zespołu inżynierów ~ 80, ale to z dobrze zdefiniowanymi podgrupami dla obszarów produktu.
Daenyth
4

Zanim coś zobowiązuje się do opanowania, programista powinien już przeprowadzić wszystkie testy jednostkowe ... ale co jeśli nie? Jeśli nie uruchomisz testów jednostkowych na serwerze CI, nie będziesz wiedział, dopóki ktoś inny nie pobierze zmian na ich komputerze i nie odkryje, że testy po prostu się na nich zepsuły.

Ponadto deweloper mógł popełnić błąd i odniósł się do lokalnego zasobu specyficznego dla ich komputera. Gdy sprawdzą kod, a uruchomienie CI nie powiedzie się, problem zostanie natychmiast zidentyfikowany i można go rozwiązać.

David Arno
źródło
3

Zakładając (w przeciwieństwie do innych odpowiedzi), że programiści są dość zdyscyplinowani i przeprowadzają testy jednostkowe przed zatwierdzeniem, może być kilka przyczyn:

  • uruchomienie testów jednostkowych może potrwać długo dla niektórych specjalnych ustawień. Na przykład uruchamianie testów jednostkowych za pomocą kontrolera pamięci (np. Valgrind) może trwać znacznie dłużej. Mimo że wszystkie testy jednostkowe przebiegają pomyślnie, sprawdzenie pamięci może się nie powieść.
  • wynik nie jest tak ważny dla niektórych specjalnych ustawień - na przykład uruchomienie testów jednostkowych w celu sprawdzenia pokrycia kodu wymaga specjalnych flag kompilacyjnych. Dla zwykłych programistów pokrycie kodu nie jest tak ważne - jest to bardziej dla osób dbających o to, by kod zachował pewną jakość, np. Kierownicy zespołów.
BЈовић
źródło
3

Można sobie wyobrazić przypadki, w których zmiana A nie przerywa testu, a zmiana B nie przerywa testu, ale A i B razem . Jeśli A i B są tworzone przez różnych programistów, tylko serwer CI wykryje nowy błąd. A i B mogą być nawet dwiema częściami tego samego dłuższego zdania.

Wyobraź sobie pociąg prowadzony przez dwie lokomotywy A i B. Może jeden jest więcej niż wystarczający i jest to poprawka do zastosowania. Jeśli jednak zastosowane zostaną dwie „poprawki” usuwające obie, pociąg się nie ruszy.

Ponadto nie wszyscy programiści wykonują wszystkie testy jednostkowe, podczas gdy większość dobrych programistów.

h22
źródło
2

Zadajmy równoważne pytanie:

Dlaczego warto zbudować kod na serwerze CI?

Z pewnością, zanim coś zostanie zobowiązane do opanowania, programista już wcześniej zbudował kod i naprawił wszelkie błędy, które mogły wystąpić w nowym kodzie. Czy nie o to chodzi w budowaniu kodu? W przeciwnym razie właśnie popełnił uszkodzony kod.


Istnieje kilka powodów, dla których warto wykonać CI, ale głównym celem CI jest zrozumienie, jaki jest stan kodu w czasie. Główną korzyścią (spośród kilku), jaką zapewnia, jest to, że możemy dowiedzieć się, kiedy kompilacja się psuje, dowiedzieć się, co ją zepsuło, a następnie naprawić.

Jeśli kod nigdy nie jest uszkodzony, dlaczego w ogóle używamy CI? Aby dostarczyć kompilacje do testowania, kompilacje nocne byłyby wystarczające.

Piotr
źródło