Strategia rozgałęziania Git zintegrowana z procesem testowania / kontroli jakości

131

Nasz zespół programistów korzysta ze strategii rozgałęziania GitFlow i było świetnie!

Niedawno zatrudniliśmy kilku testerów, aby poprawić jakość naszego oprogramowania. Chodzi o to, że każda funkcja powinna zostać przetestowana / QA przez testera.

W przeszłości programiści pracowali nad funkcjami w oddzielnych gałęziach funkcji i po zakończeniu scalali je z powrotem do developgałęzi. Deweloper sam przetestuje swoją pracę w tej featuregałęzi. Teraz z testerami zaczynamy zadawać to pytanie

W której gałęzi tester powinien testować nowe funkcje?

Oczywiście są dwie możliwości:

  • na poszczególnych gałęziach funkcji
  • na developgałęzi

Testowanie na gałęzi Develop

Początkowo wierzyliśmy, że jest to pewna droga, ponieważ:

  • Ta funkcja jest testowana ze wszystkimi innymi funkcjami połączonymi z developgałęzią od momentu rozpoczęcia jej opracowywania.
  • Wszelkie konflikty można wykryć wcześniej niż później
  • Ułatwia to pracę testera, ma on do czynienia przez developcały czas tylko z jedną gałęzią ( ). Nie musi pytać dewelopera, która gałąź jest dla której funkcji (gałęzie funkcji to osobiste gałęzie zarządzane wyłącznie i swobodnie przez odpowiednich programistów)

Największe problemy z tym to:

  • developOddział jest zanieczyszczona z robakami.

    Gdy tester znajdzie błędy lub konflikty, zgłasza je z powrotem do programisty, który naprawia problem w gałęzi deweloperskiej (gałąź funkcji została porzucona po scaleniu), a później może być wymaganych więcej poprawek. Wielokrotne zatwierdzanie lub scalanie podciągów (jeśli gałąź jest ponownie tworzona z developgałęzi w celu naprawienia błędów) sprawia, że ​​wycofanie funkcji z developgałęzi jest bardzo trudne, jeśli to możliwe. Istnieje wiele funkcji łączących się i naprawianych w developgałęzi w różnym czasie. Stwarza to duży problem, gdy chcemy utworzyć wydanie z tylko niektórymi funkcjami w developgałęzi

Testowanie na gałęzi funkcji

Więc pomyśleliśmy jeszcze raz i zdecydowaliśmy, że powinniśmy przetestować funkcje w gałęziach funkcji. Zanim przetestujemy, scalamy zmiany z developgałęzi do gałęzi funkcji (doganiamy developgałąź). To jest dobre:

  • Nadal testujesz tę funkcję z innymi funkcjami w głównym nurcie
  • Dalszy rozwój (np. Naprawa błędów, rozwiązywanie konfliktów) nie zanieczyszcza developgałęzi;
  • Możesz łatwo zdecydować, aby nie udostępniać tej funkcji, dopóki nie zostanie w pełni przetestowana i zatwierdzona;

Istnieją jednak pewne wady

  • Tester musi dokonać scalenia kodu, a jeśli wystąpi jakikolwiek konflikt (bardzo prawdopodobne), musi poprosić programistę o pomoc. Nasi testerzy specjalizują się w testowaniu i nie potrafią kodować.
  • funkcja mogłaby zostać przetestowana bez istnienia innej nowej funkcji. Np. funkcja A i B są testowane w tym samym czasie, dwie funkcje nie są sobie znane, ponieważ żadna z nich nie została scalona z developodgałęzieniem. Oznacza to, że będziesz musiał ponownie przetestować tę developgałąź, gdy obie funkcje i tak zostaną scalone z gałęzią deweloperską. I musisz pamiętać, aby przetestować to w przyszłości.
  • Jeśli funkcja A i B są zarówno przetestowane, jak i zatwierdzone, ale po połączeniu zostanie zidentyfikowany konflikt, obaj programiści dla obu funkcji uważają, że nie jest to jego własna wina / zadanie, ponieważ jego gałąź funkcji przeszła test. Komunikacja wiąże się z dodatkowymi kosztami i czasami ten, kto rozwiązuje konflikt, jest sfrustrowany.

Powyżej znajduje się nasza historia. Mając ograniczone zasoby, chciałbym uniknąć testowania wszystkiego wszędzie. Nadal szukamy lepszego sposobu radzenia sobie z tym. Bardzo chciałbym usłyszeć, jak inne zespoły radzą sobie w tego typu sytuacjach.

David Lin
źródło
5
Wydaje się, że to pytanie lepiej pasuje do programistów , ponieważ nie dotyczy problemu programistycznego, ale raczej proces rozwoju. Czy ktoś może go przenieść?
2
Nasz model jest dokładnie taki sam. Interesuje mnie, jak Twój zespół QA zgłasza problemy dotyczące gałęzi funkcji inaczej niż problemy w terenie lub problemy podczas procesu UAT (jeśli taki masz). Używamy Atlassian JIRA i mamy dla nich inny przepływ pracy.
void.pointer
2
Decydowanie teraz o tym samym. Ponadto, ponieważ nasze środowisko jest aplikacją Java Spring, zbudowanie i wdrożenie w środowisku testowym zajmuje około 20 minut. Szczęśliwy ktoś zapytał te same wątpliwości co ja.
digao_mb
Pierwsza wada nie jest nieodłączna dla procesu testowania gałęzi funkcji. Narzędzia takie jak Github Enterprise i Bitbucket mogą wymagać zatwierdzenia dla żądań ściągnięcia, a osoba odpowiedzialna za kontrolę jakości może zatwierdzić zasygnalizowanie programistom, że mogą swobodnie scalać się w programowanie.
Derek Greer

Odpowiedzi:

102

Sposób, w jaki to robimy, jest następujący:

Testujemy na gałęziach funkcji po scaleniu na nich najnowszego kodu gałęzi deweloperskiej. Głównym powodem jest to, że nie chcemy „zanieczyszczać” kodu gałęzi deweloperskiej przed zaakceptowaniem funkcji. Gdyby jakaś funkcja nie została zaakceptowana po testach, ale chcielibyśmy wydać inne funkcje już scalone w fazie rozwoju, byłoby to piekło. Develop jest gałęzią, z której dokonywane jest wydanie i dlatego powinien być w stanie umożliwiającym wydanie. Długa wersja jest taka, że ​​testujemy w wielu fazach. Bardziej analitycznie:

  1. Deweloper tworzy gałąź funkcji dla każdej nowej funkcji.
  2. Gałąź funkcji jest (automatycznie) wdrażana w naszym środowisku TEST z każdym zatwierdzeniem do przetestowania przez programistę.
  3. Gdy programista zakończy wdrażanie, a funkcja jest gotowa do przetestowania, łączy gałąź deweloperską w gałęzi funkcji i wdraża gałąź funkcji, która zawiera wszystkie najnowsze zmiany programistyczne w TEST.
  4. Tester wykonuje testy na TEST. Kiedy skończy, „akceptuje” historię i łączy gałąź fabularną na develop. Ponieważ deweloper wcześniej połączył gałąź deweloperską z funkcją, zwykle nie spodziewamy się zbyt wielu konfliktów. Jednak w takim przypadku programista może pomóc. To trudny krok, myślę, że najlepszym sposobem na uniknięcie tego jest utrzymywanie funkcji tak małych / szczegółowych, jak to tylko możliwe. Różne funkcje muszą ostatecznie zostać połączone, w taki czy inny sposób. Oczywiście wielkość zespołu ma wpływ na złożoność tego etapu.
  5. Gałąź deweloperska jest również (automatycznie) wdrażana na TEST. Mamy zasadę, że nawet jeśli kompilacja gałęzi funkcji może zawieść, gałąź deweloperska nigdy nie powinna zawieść.
  6. Po osiągnięciu zamrożenia funkcji tworzymy wydanie z develop. Jest to automatycznie wdrażane w STAGING. Przed wdrożeniem produkcyjnym odbywają się tam szeroko zakrojone testy od początku do końca. (ok, może trochę przesadzam, nie są zbyt rozbudowane, ale myślę, że powinny). Najlepiej byłoby, gdyby testerzy / koledzy, czyli prawdziwi użytkownicy, testowali tam.

Co myślisz o tym podejściu?

Aspazja
źródło
2
W jaki sposób upewniamy się, że cecha 1 i cecha 2, które zostały przetestowane niezależnie, również dobrze współgrają (jak wspomniano w pytaniu)?
Kumar Deepak,
2
robimy pośrednio, łącząc jedną, a potem drugą, aby się rozwijać. Jest to krok 4 powyższego procesu i ma związek z porządkiem chronologicznym. Jeśli więc funkcja 2 jest gotowa do połączenia, ale funkcja 1 została już scalona, ​​deweloper i tester funkcji 2 muszą upewnić się, że ich scalenie będzie działać.
Aspasia
1
Myślę, że tak czy inaczej, zgodnie z tym modelem rozgałęziania git nie powinno się łączyć ze sobą dwóch gałęzi funkcji.
Aspasia,
1
Napotkaliśmy problemy w kroku 6, szczególnie w czasach kryzysu, kiedy wiele funkcji zostało przeniesionych do rozwoju, z powodu nietrywialnych połączeń, które mają miejsce po wylogowaniu się z QA w gałęzi funkcji, pomimo scalania devlop do funkcji tak późno, jak to możliwe. Trochę bardziej szczegółowo skomentowałem tutaj: stackoverflow.com/a/25247382/411282
Joshua Goldberg
8
Czy masz pełne środowisko testowe (baza danych, serwer, klient itp.) Dla każdej gałęzi funkcji? Czy też mają wspólne środowisko i po prostu mają różne nazwy (np. Nazwa-aplikacji_funkcja1- nazwa-aplikacji_funkcja2 itp.)
hinneLinks
41

Przed testem scalamy zmiany z gałęzi deweloperskiej do gałęzi funkcji

Nie. Nie rób tego, zwłaszcza jeśli „my” jest testerem kontroli jakości. Scalanie wymagałoby rozwiązywania potencjalnych konfliktów, co najlepiej robią programiści (znają swój kod), a nie tester QA (który powinien jak najszybciej przystąpić do testów).

Spraw, aby deweloper wykonał rebase swojej featuregałęzi na wierzchudevel i wypchnął tę featuregałąź (która została zatwierdzona przez dewelopera jako kompilująca i pracująca na najnowszym develstanie gałęzi).
To pozwala na:

Za każdym razem, gdy tester wykryje błąd, zgłosi go deweloperowi i usunie bieżącą gałąź funkcji.
Deweloper może:

  • naprawić błąd
  • rebase na podstawie niedawno pobranej gałęzi deweloperskiej (ponownie, aby mieć pewność, że jego / jej kod działa w integracji z innymi sprawdzonymi funkcjami)
  • pchnij featuregałąź.

Ogólny pomysł: upewnij się, że część scalająca / integracyjna jest wykonywana przez programistę, pozostawiając testowanie kontroli jakości.

VonC
źródło
Czy mówisz „nie używaj scalania, zamiast tego użyj rebase”? Jeśli tak, jestem zdezorientowany, biorąc pod uwagę Git FAQ na temat różnicy między nimi: git.wiki.kernel.org/index.php/ ...
Vicki Laidler
1
@VickiLaidler tak, jeśli gałąź funkcji zostanie odrzucona przez kontrolę jakości, programista musi zmienić bazę, a nie scalić ( stackoverflow.com/a/804178/6309 )
VonC
1
@VonC Całkowicie się zgadzam, ale są pewne problemy: 1) Usunięcie gałęzi wpływa na inne narzędzia, takie jak Stash Pull Requests (usunięcie gałęzi zamyka PR). Preferuj pchanie siłowe. 2) Jeśli jest to duża gałąź funkcji, w której w czasie swojego życia współpracowały dwie osoby, fuzje byłyby preferowane niż zmiana bazy. Ponowne wprowadzenie go na końcu tworzy koszmar konfliktu, ponieważ zatwierdzenia scalania zostaną usunięte, a jeśli kod zależał od tych zmian scalania, naprawa jest nietrywialna
void.pointer
1
Patrząc wstecz na moją odpowiedź, również dokonałbym rebase'u, a nie scalenia dla czystszej historii.
Aspasia
1
@Aspasia Dobre punkty. Uwzględniłem żądania ściągnięcia w odpowiedzi, aby uzyskać lepszą widoczność.
VonC
12

Najlepszym podejściem jest ciągła integracja , gdzie ogólna idea polega na jak najczęstszym scalaniu gałęzi funkcji w gałąź deweloperską. Zmniejsza to koszty związane z bólami łączenia.

W miarę możliwości polegaj na testach automatycznych, a kompilacje automatycznie rozpoczynają się od testów jednostkowych Jenkinsa. Niech programiści wykonają całą pracę, łącząc swoje zmiany z główną gałęzią i dostarczają testy jednostkowe dla całego swojego kodu.

Testerzy / QA mogą brać udział w przeglądach kodu, sprawdzać testy jednostkowe i pisać automatyczne testy integracyjne, które zostaną dodane do zestawu regresji po ukończeniu funkcji.

Aby uzyskać więcej informacji, sprawdź ten link .

Johnny Z
źródło
Nadal możesz wykonywać CI z oddziałami i ponownym bazowaniem w Git.
void.pointer
9

Używamy tego, co nazywamy „złotem”, „srebrem” i „brązem”. Można to nazwać prod, staging i qa.

Zacząłem nazywać to modelem tygla. To działa dobrze dla nas, ponieważ mamy ogromne zapotrzebowanie na QA po stronie biznesowej, ponieważ wymagania mogą być trudne do zrozumienia w porównaniu z technicznymi.

Gdy błąd lub funkcja jest gotowa do testowania, przechodzi na „brązowy medal”. To wyzwala kompilację Jenkinsa, która wypycha kod do wstępnie zbudowanego środowiska. Nasi testerzy (nawiasem mówiąc, nie super technicy) po prostu klikają link i nie dbają o kontrolę źródła. Ta kompilacja uruchamia również testy itp. W tej kompilacji wielokrotnie przenosiliśmy kod do środowiska testowego \ qa, jeśli testy (jednostka, integracja, selen) zawiodły. Jeśli testujesz na oddzielnym systemie (nazywamy to leadem), możesz zapobiec wypychaniu zmian do twojego środowiska QA.

Początkowo obawiano się, że będziemy mieli wiele konfliktów między tymi funkcjami. Zdarza się, że funkcja X sprawia wrażenie, że funkcja Y się psuje, ale jest to dość rzadkie i faktycznie pomaga. Pomaga uzyskać szeroki zakres testów poza tym, co wydaje się być kontekstem zmiany. Wiele razy przez szczęście dowiesz się, jak Twoja zmiana wpływa na równoległy rozwój.

Gdy funkcja przejdzie kontrolę jakości, przenosimy ją na „srebrną” lub etapową. Kompilacja jest uruchamiana, a testy są ponownie uruchamiane. Co tydzień wprowadzamy te zmiany do naszego „złota” lub drzewa produktów, a następnie wdrażamy je w naszym systemie produkcyjnym.

Deweloperzy rozpoczynają zmiany od złotego drzewka. Technicznie rzecz biorąc, możesz zacząć od inscenizacji, ponieważ wkrótce pojawią się.

Awaryjne poprawki są umieszczane bezpośrednio w drzewie złota. Jeśli zmiana jest prosta i trudna do QA, może przejść bezpośrednio do srebra, które trafi do drzewka testów.

Po wydaniu wprowadzamy zmiany w złocie (prod) na brąz (testowanie), aby wszystko było zsynchronizowane.

Możesz chcieć ponownie ustawić bazę przed wysłaniem do folderu przemieszczania. Odkryliśmy, że od czasu do czasu czyszczenie drzewa testowego utrzymuje je w czystości. Są chwile, kiedy funkcje są porzucane w drzewie testowym, zwłaszcza jeśli programista odchodzi.

W przypadku dużych funkcji dla wielu programistów tworzymy oddzielne współdzielone repozytorium, ale scalamy je w drzewo testowe tak samo, gdy wszyscy jesteśmy gotowi. Rzeczy mają tendencję do odbijania się od kontroli jakości, więc ważne jest, aby izolować zestawy zmian, aby można było dodawać, a następnie scalać / zgniatać w drzewie przemieszczania.

Miłym efektem ubocznym jest też „pieczenie”. Jeśli masz jakąś zasadniczą zmianę, na którą chcesz odpocząć, jest na to fajne miejsce.

Pamiętaj też, że nie obsługujemy poprzednich wersji. Aktualna wersja jest zawsze jedyną wersją. Mimo to prawdopodobnie możesz mieć główne drzewo do pieczenia, w którym Twoi testerzy lub społeczność będą mogli zobaczyć, jak różne rzeczy współpracowników wchodzą w interakcje.

Eric Twilegar
źródło
1

Nie polegałbym wyłącznie na testach ręcznych. Zautomatyzowałbym testowanie każdej gałęzi funkcji za pomocą Jenkinsa. Skonfigurowałem laboratorium VMWare, aby uruchamiać testy Jenkins w systemie Linux i Windows dla wszystkich przeglądarek. To naprawdę niesamowite rozwiązanie do testowania między przeglądarkami i platformami. Testuję funkcjonalność / integrację z Selenium Webdriver. Moje testy selenu prowadzone pod Rspec. Napisałem je specjalnie do ładowania przez jRuby w systemie Windows. Przeprowadzam tradycyjne testy jednostkowe w ramach testów Rspec i Javascript w Jasmine. Skonfigurowałem testowanie bezgłowe z Phantom JS.

Natus Drew
źródło
1

W naszej firmie nie możemy stosować zwinnego rozwoju i potrzebujemy zgody na każdą zmianę biznesową, co powoduje wiele problemów.

Nasze podejście do pracy z GIT jest następujące;

W naszej firmie wdrożyliśmy „Git Flow”. Używamy JIRA i tylko zatwierdzone bilety JIRA powinny być kierowane do produkcji. W celu zatwierdzenia testu rozszerzyliśmy go o utworzony oddzielny oddział testowy.

Kroki przetwarzania biletów JIRA:

  1. Utwórz nową gałąź z Develop-Branch
  2. Wykonaj zmiany kodu w gałęzi Feature
  3. Wyciągnij z funkcji zmiany w gałęzi Test / QA
  4. Po zatwierdzeniu biznesowym przeciągamy zmianę z gałęzi funkcji na development
  5. Rozwijanie odbywa się często w wydaniu, a następnie w gałęzi master

Dzielenie każdego żądania na własną funkcję zapewnia, że ​​tylko zatwierdzone zmiany trafią do produkcji.

Cały proces wygląda następująco: wprowadź opis obrazu tutaj

Christian Müller
źródło