Przyspieszenie testów RSpec w dużej aplikacji Railsowej

91

Mam aplikację Railsową z ponad 2000 przykładów w moich testach RSpec. Nie trzeba dodawać, że jest to duża aplikacja i jest wiele do przetestowania. Uruchamianie tych testów w tym momencie jest bardzo nieefektywne, a ponieważ trwa to tak długo, jesteśmy prawie na etapie zniechęcenia do ich pisania przed wypchnięciem nowej kompilacji. Dodałem --profile do moich specyfikacji. Pozwala znaleźć najdłużej działające przykłady i jest co najmniej 10 z nich, których uruchomienie zajmuje średnio 10 sekund. Czy to normalne wśród ekspertów RSpec? Czy w jednym przykładzie 10 sekund jest zbyt długie? Zdaję sobie sprawę, że w przypadku 2000 przykładów dokładne przetestowanie wszystkiego zajmie niebanalną ilość czasu - ale w tym momencie 4 godziny to trochę śmieszne.

Jakie czasy widzisz dla swoich najdłużej działających przykładów? Co mogę zrobić, aby rozwiązać problemy z istniejącymi specyfikacjami, aby znaleźć wąskie gardła i przyspieszyć działanie. W tym momencie każda minuta naprawdę pomogłaby.

randombity
źródło
1
Czy powolne testy są testami integracyjnymi? Czy uderzają w db? Jeśli tak, to jak często baza danych jest ponownie ładowana i czy możesz z niej kpić?
Kaleb Pederson,
1
Czy jesteś w stanie po prostu uruchomić część specyfikacji, które są istotne dla części, nad którą pracujesz, podobnie jak autotest SeattleRB? Czy masz serwer ciągłej integracji, na którym można przeprowadzić wszystkie testy?
Andrew Grimm,
Pamiętaj też, że wszystkie rzeczy są względne. Słyszałem, że "grrr, nasz zestaw testów trwa wiecznie" zarówno przez 20 minut ... jak i 16-20 godzin. Wszystko zależy od patrzącego. 10 sekund dla danego testu często oznacza test jednostkowy, który stał się testem integracyjnym, jak wspomniano poniżej.
Michael Durrant,
Sugestia dla tego rodzaju problemu: używaj perftools.rbrazem z platformą testową, aby zrozumieć, co pochłania większość czasu. Odbierz 10 najlepszych połączeń i spróbuj je wyeliminować / przejrzeć. Następnie powtarzaj, aż będziesz szczęśliwy.
aledalgrande

Odpowiedzi:

118

10 sekund to bardzo długi czas na wykonanie pojedynczego testu. Moje przeczucie jest takie, że Twój cel specyfikacji przeprowadza jednocześnie testy jednostkowe i testy integracji. Jest to typowa rzecz, w którą wpadają projekty i na pewnym etapie będziesz musiał pokonać ten dług techniczny, jeśli chcesz produkować więcej i szybciej. Istnieje wiele strategii, które mogą ci w tym pomóc ... a ja polecę kilka z nich, z których korzystałem w przeszłości.

1. Oddzielna jednostka od testów integracji

Pierwszą rzeczą, którą bym zrobił, to oddzielenie jednostki od testów integracyjnych. Możesz to zrobić:

  1. Przenoszenie ich (do oddzielnych folderów w katalogu spec) - i modyfikowanie celów rake
  2. Oznaczanie ich (rspec umożliwia tagowanie testów)

Filozofia głosi, że chcesz, aby twoje regularne kompilacje były szybkie - w przeciwnym razie ludzie nie będą zbyt szczęśliwi, aby je często uruchamiać. Więc wracaj na to terytorium. Skorzystaj z szybkiego uruchamiania regularnych testów i używaj serwera ciągłej integracji, aby uruchomić bardziej kompletną kompilację.

Test integracji to test obejmujący zewnętrzne zależności (np. Baza danych, usługa sieciowa, kolejka, a niektórzy twierdzą, że system plików). Test jednostkowy po prostu testuje określony element kodu, który chcesz sprawdzić. Powinien działać szybko (możliwe jest 9000 w 45 sekund), tj. Większość z nich powinna działać w pamięci.

2. Przekształć testy integracji w testy jednostkowe

Jeśli większość testów jednostkowych jest mniejsza niż zestaw testów integracyjnych, masz problem. Oznacza to, że niespójności zaczną pojawiać się łatwiej. Od tego momentu zacznij tworzyć więcej testów jednostkowych, aby zastąpić testy integracyjne. Możesz pomóc w tym procesie:

  1. Użyj fałszywego frameworka zamiast prawdziwego zasobu. Rspec ma wbudowany framework do mockowania.
  2. Uruchom rcov na swoim zestawie testów jednostkowych. Użyj tego, aby ocenić, jak dokładny jest twój zestaw testów jednostkowych.

Gdy masz już odpowiednie testy jednostkowe, które zastąpią test integracji - usuń test integracji. Podwójne testowanie tylko pogarsza konserwację.

3. Nie używaj urządzeń

Urządzenia są złe. Zamiast tego użyj fabryki (mechanika lub robota fabrycznego). Systemy te mogą budować bardziej adaptowalne wykresy danych, a co ważniejsze, mogą budować obiekty w pamięci, których możesz używać, zamiast ładować rzeczy z zewnętrznego źródła danych.

4. Dodaj kontrole, aby powstrzymać testy jednostkowe jako testy integracji

Teraz, gdy masz już szybsze testy, czas na sprawdzenie, aby to ZATRZYMAĆ.

Istnieją biblioteki, które małpa poprawiają rekord aktywny, aby zgłosić błąd podczas próby uzyskania dostępu do bazy danych (UnitRecord).

Możesz także spróbować parowania i TDD, które mogą zmusić Twój zespół do pisania szybszych testów, ponieważ:

  1. Ktoś sprawdza - żeby nikt nie był leniwy
  2. Właściwe TDD wymaga szybkiej informacji zwrotnej. Powolne testy sprawiają, że cała sprawa jest bolesna.

5. Użyj innych bibliotek, aby rozwiązać problem

Ktoś wspomniał o spork (przyspiesza ładowanie zestawu testów pod szynami3), hydra / parallel_tests - aby uruchomić testy jednostkowe równolegle (na wielu rdzeniach).

Prawdopodobnie powinno to być używane OSTATNIE. Twój prawdziwy problem pojawia się w kroku 1, 2, 3. Rozwiąż go, a będziesz w lepszej pozycji do odgrywania dodatkowej infrastruktury.

BlueFish
źródło
Świetna odpowiedź. Prawdą jest, że żadne zaawansowane narzędzia nie mogą pomóc w szybkim przeprowadzeniu złych testów. Spróbuj więc pisać tylko dobre.
Yura Omelchuk
5
Nie zgadzam się z Twoją trzecią uwagą, że nie powinieneś używać urządzeń. Jeśli są właściwie używane, są szybsze niż fabryki, ponieważ nie musisz tworzyć obiektów. Twoje dane są tam, więc nie musisz ich tworzyć przy każdym przypadku testowym.
wallerjake
3
To o tym, że fabryki są szybsze, to żart, prawda?
Mike Szyndel
Przyspiesz testy, selektywnie unikając Factory Girl - robots.thoughtbot.com/…
geekdev
16

Aby uzyskać świetną książkę kucharską na temat poprawy wydajności zestawu testów, zapoznaj się z prezentacją Grease Your Suite .

Dokumentuje 45-krotne przyspieszenie w czasie wykonywania zestawu testów, wykorzystując takie techniki, jak:

marszowo
źródło
Lubię linki, ale nie prezentację. Karty indeksowe do czyjegoś przemówienia to zachęta dla prelegenta do uzupełnienia treści prezentacji.
Brian Maltzan
Ta prezentacja już nie działa. fast_context przyspiesza działanie wielu bloków shoulda. quickerclip (ten link również nie działa) najwyraźniej przyspiesza spinacz. Hydra jest przestarzała dla parallel_tests i Gorgon. Bootsnap ma poprawki w systemie plików i jest teraz dołączony do Railsów. Najnowsze wersje Rubiego mają ulepszoną alokację i GC.
rep
5

Możesz użyć Spork. Obsługuje 2.3.x,

https://github.com/sporkrb/spork

lub ./script/spec_server, który może działać w wersji 2.x

Możesz także edytować konfigurację bazy danych (co zasadniczo przyspiesza zapytania do bazy danych itp.), Co również zwiększy wydajność testów.

Rishav Rastogi
źródło
Spork jest niesamowity. Działa również na Railsach 3, z odrobiną hakowania. Ale jedną rzeczą, na którą należy zwrócić uwagę w przypadku Spork on Rails 3, jest to, że nie wydaje się wychwytywać zmian w kontrolerach, więc będziesz musiał co jakiś czas uruchamiać go ponownie. W każdym razie, Spork jest naprawdę niesamowity, poprawa szybkości testów jest bardzo znacząca.
About Ruby,
4
Spork służy tylko do przyspieszenia uruchamiania, a nie testów. Tak więc przy wielu specyfikacjach przewaga jest nieznaczna.
Reactormonk
Wbrew powyższym komentarzom, spork może być użyty do przyspieszenia testów, a także uruchomienia, jak na railscast railscasts.com/episodes/285-spork . Znacznie ulepszyłem mój zestaw testów rspec w bardzo dużej aplikacji. (Zmniejszono ze 192 do 10 sekund!)
jamesc
3

10 sekund na przykład wydaje się bardzo długim czasem. Nigdy nie widziałem specyfikacji, która zajmowała więcej niż jedną sekundę, a większość zajmuje znacznie mniej. Czy testujesz połączenia sieciowe? Baza danych pisze? System plików pisze?

Używaj makiet i kodów pośredniczących tak często, jak to możliwe - są one znacznie szybsze niż pisanie kodu, który trafia do bazy danych. Niestety kpiny i klepanie również zajmuje więcej czasu (i jest trudniejsze do wykonania poprawnie). Musisz zrównoważyć czas spędzony na pisaniu testów z czasem spędzonym na wykonywaniu testów.

Po drugie, wypowiedź Andrew Grimma na temat przyjrzenia się systemowi CI, który może pozwolić na zrównoleglenie zestawu testów. Dla czegoś tej wielkości może to być jedyne realne rozwiązanie.

zetetic
źródło
tak, jeśli to 10 sekund,
sprofilowałbym
1
Mam ogromny projekt i wykonanie pojedynczego testu rspec zajmuje około 15-20 sekund.
ExiRe
2

Kilka osób wspomniało powyżej o Hydrze. W przeszłości używaliśmy go z dużym powodzeniem. Niedawno udokumentowałem proces uruchomienia i uruchomienia hydry: http://logicalfriday.com/2011/05/18/faster-rails-tests-with-hydra/

Zgodziłbym się z opinią, że tego rodzaju technika nie powinna zastępować pisania testów, które domyślnie mają dobrą strukturę i są szybkie.

Rodreegez
źródło
0

Możesz skorzystać z kilku prostych wskazówek, aby najpierw zbadać, gdzie spędza się większość czasu, jeśli jeszcze ich nie wypróbowałeś. Spójrz na poniższy artykuł:

https://blog.mavenhive.in/7-tips-to-speed-up-your-webdriver-tests-4f4d043ad581

Myślę, że większość z nich to ogólne kroki, które można by zastosować niezależnie od narzędzia używanego do testowania.

jake
źródło
-4

Usuń istniejący zestaw testów. Będzie niesamowicie skuteczny.

thedanotto
źródło