Mockowanie a wydajność

0

U mojego klienta mamy trochę ponad 3000 testów jednostkowych, których odpalenie zajmuje ok. 7-8 minut. Średnio daje to ok. 0,13s per test. Ponieważ chcemy uruchamiać wszystkie testy przy każdym deploymencie (także każdej instancji testowej), zależy nam na skróceniu tego czasu. Zauważyłem, że testy, w których nie są mockowane żadne obiekty, wykonują się w granicach 1-3ms, w pozostałych czas znacznie rośnie (w zależności do ilości mockowanych obiektów). Korzystamy z Rhino Mocks. Zastanawiam się, czy waszym zdaniem realne jest znaczne skrócenie średniego czasu - być może da się zastosować jakieś triki z globalnym cacheowaniem mocków; niczego w necie nie udało mi się znaleźć. I generalnie, czy taki rząd średniego czasu jest mocno zawyżony, jak to u Was wygląda?

0

Dlaczego uruchamiacie testy jednostkowe przy deploymencie, a nie po buildzie?

0

Sorry, oczywiście puszczamy po buildzie, przed deploymentem. W każdym razie cały proces długo trwa przez konieczność odpalenia testów.

0

Testy odpalane lokalnie też tyle trwają? Próbowałeś je jakoś profilować?

0

Lokalnie czas jest podobny (nawet trochę dłuższy ze względu na wydajność maszyny). Trochę wybadałem temat i niestety wydaje mi się, że żadnej magicznej sztuczki tutaj nie zastosuję. Mockowania jest bardzo dużo, mockowane klasy są często bardzo ciężkie (pewnie to wydłuża czas mockowania, więcej refleksji pod spodem). Trzeba sporo bindować (wiele klas używa NinjectLocatora niestety). Poza tym sama logika jest dość złożona, więc nie wierzę, że da się tu uzyskać średni czas rzędu milisekundy. Znalazłem taki wątek na stackoverflow:

http://stackoverflow.com/questions/3824762/how-slow-is-too-slow-for-unit-tests

Gość ma podobne czasy jak ja (najdłuższe ze względu właśnie na mocki), a najlepsza rada, jaką dostał, to podzielić testy na grupę krytycznych (wykonywanych szybko i zawsze po buildzie) i pozostałych (które mogą się wykonywać kilka minut, kiedy są wolne zasoby).

1
Hrypa napisał(a):

Gość ma podobne czasy jak ja (najdłuższe ze względu właśnie na mocki), a najlepsza rada, jaką dostał, to podzielić testy na grupę krytycznych (wykonywanych szybko i zawsze po buildzie) i pozostałych (które mogą się wykonywać kilka minut, kiedy są wolne zasoby).

To jakby zaburza trochę ideę CI. No, ale jeśli część testów jest, że tak powiem, bardziej integracyjna od innych, to może się udać.
Chociaż ja bym i tak spróbował profilować, bo może się okazać, że przez jakiś prosty błąd (typu Thread.Sleep w pętli) coś wykonuje się w absurdalnym czasie.

0

U nas testy są podzielone na dwa kawałki, część testującą najczęściej modyfikowane elementy systemu i część testującą wszystko. Są to stare zależności, bo kiedyś testy całości zajmowały pół godziny, po znalezieniu i zlikwidowaniu dziury jedno i drugie wykonuje się na agencie Team City poniżej 10 minut (z tego powodu te dwie grupy testów kiedyś zostaną złączone). 10-15 minut (czasem trochę więcej, bo TC może być zajęte innymi projektami) jest to całkowicie akceptowalnym czasem. Dlaczego? Bo:

  • część testów, które bezpośrednio dotykają modyfikowanego kodu, uruchamiasz lokalnie u siebie (sam wybierasz które) i trwa to kilkanaście-kilkadziesiąt sekund,
  • testy na TC odbywają się automatycznie po każdym commicie i całkowicie w tle, jeśli coś spieprzysz i kod się nie skompiluje albo któryś test się wywali dostajesz maila (bo to po Twoim commicie coś nie działa) i wiesz, że to Ty coś spiertentego,
  • nie jest problemem, że musisz poczekać te 10-15 minut na TC, bo nie musisz czekać z dalszym pisaniem kodu, przecież nie zapomnisz po kwadransie co miałeś na myśli w wywalającym się miejscu.
    Testy powinny wykonywać się po każdym commicie (lub grupami, jeśli commity są bardzo częste), zanim zrobi się jakakolwiek paczka z deploy'em. Jeśli uruchamiacie testy jednostkowe u klienta (mocki!!! po co sprawdzać mocki u klienta?!), to coś wam się pomyliło.
0

Dzięki za pomoc. Z tym "klientem" to też niefortunne określenie. Nie chodziło mi o odbiorcę softu, tylko o firmę dla której pracuję. Puszczanie testów po każdym pushu nie wchodzi w grę, bo zarżnęlibyśmy maszynę. Cały czas mówię tu nie o finalnym deploymencie, czy nawet jakichś UATach, a o deweloperskich środowiskach testowych, których mamy setki. Nie po każdym pushu chcemy publikować zmiany na deweloperskie środowisko testowe, często kod nie jest jeszcze gotowy i z góry wiadomo, że testy nie przejdą (znowu podkreślam, chodzi o pushowanie do poszczególnych deweloperskich branchy).
@somekind dzięki za sugestię. Sprawdziłem dotTracem i faktycznie, spory fragment czasu zabiera rhino mocks. Ale znaczna większość idzie na Ninject:/ Mała część na faktyczną logikę biznesową. Będę jeszcze kombinował, co z tym fantem zrobić.

1

7-8 minut to aż taki problem? 2 godziny lub więcej to rozumiem, jest wtedy o co walczyć.
Jeśli jest dużo developerów (dużo branchy równocześnie), to maszyna integracyjna powinna robić testy jedynie dla comitów do master lub na ręczne żądanie.
Jakoś nie chce mi się wierzyć, że merge do master macie częściej niż co 30 minut.

0

@Hrypa, setki środowisk testowych? To co Wy za soft piszecie?

Zawsze można robić build + testy nie po każym commicie, tylko np. co jakiś czas, albo zgodnie z wolnymi zasobami, TeamCity takie coś potrafi. Zysk taki, że maszyna się nie męczy, minus taki, że nie wiadomo dokładnie kto zepsuł testy.
No, a inna rzecz, że może po prostu trzeba więcej build agentów.

0

@MarekR22
Master oczywiście zmienia się rzadko, tutaj nie ma najmniejszego problemu. Być może rzeczywiście testy nie powinny być puszczane dla wszystkich testowych środowisk, a tylko dla tych integracyjnych/releasowych. Ale to już nie moja decyzja i nie mam na to wpływu. Szczerze mówiąc też mi się wydaje, że te 7-8 minut to nie jest tak dużo i szukałem potwierdzenia na forum:) Ale dostałem zadanie próby skrócenia tego czasu, klient nasz pan.

@somekind
Mamy akurat taki model, że każdy najmniejszy tickecik (łącznie z podmianką tekstu na jakiejś stronie) jest najpierw robiony w osobnym branchu. Kod tego brancha jest publikowany na osobne środowisko testowe (wtedy właśnie puszczane są testy o których mowa). Dopiero po przetestowaniu, zmiana trafia do releasu i jest mergowana do kolejnego integracyjnego brancha (na tym etapie puszczane są wszystkie testy łącznie z integracyjnymi, trwa to koło godziny i nie ma z tym problemu).

1

Trochę dziwne to Wasze podejście. Moim zdaniem programista powinien naprawiać błąd na branchu jakim chce, odpalić testy lokalnie, jeśli przechodzą to wrzucać poprawkę do brancha hotfix, a ten jest kompilowany, testowany jeszcze raz, wrzucany na środowiska testerskie, itd.

0

@somekind
Przede wszystkim nie mowa tu o naprawianiu bugów, a o nowych funkcjonalnościach (takie CR-y). Programista może sobie dewelopować na jakim branchu chce; chodzi tylko o to, że w momencie kiedy chce swoje zmiany wysłać do testów (długo przed wrzucaniem ich do jakiegokolwiek integracyjnego brancha), muszą zostać odpalone wszystkie unit testy.

Okazuje się, że przed każdym test casem jest odpalana metoda resetująca wszystkie bindingi, stąd taki kosmiczny narzut na Ninject.

0
Hrypa napisał(a):

@somekind
Przede wszystkim nie mowa tu o naprawianiu bugów, a o nowych funkcjonalnościach (takie CR-y). Programista może sobie dewelopować na jakim branchu chce; chodzi tylko o to, że w momencie kiedy chce swoje zmiany wysłać do testów (długo przed wrzucaniem ich do jakiegokolwiek integracyjnego brancha), muszą zostać odpalone wszystkie unit testy.

No i dlaczego nie robić tego lokalnie?

Okazuje się, że przed każdym test casem jest odpalana metoda resetująca wszystkie bindingi, stąd taki kosmiczny narzut na Ninject.

A to chyba powinno się dać jakoś poprawić.

0
somekind napisał(a):

No i dlaczego nie robić tego lokalnie?

Oczywiście, najlepiej to robić lokalnie. Ale nie zmusisz wszystkich deweloperów, żeby to robili. Jeżeli odpalisz unit testy dopiero na branchu integracyjnym i któryś test się wywali, trzeba będzie chwilę poszukać, który commit zepsuł test. Może to mimo wszystko lepsze podejście, ale jak napisałem, nie moja decyzja.

somekind napisał(a):

A to chyba powinno się dać jakoś poprawić.

Już to robię:) Wstępnie czas testów spadł o jakieś 90%, ale niektóre zaczęły się wywalać (ponieważ niektóre testy mają swoje rebindy, co wpływa na inne testy jeżeli po każdym nie następuje reset - ale z tym sobie już poradzę).

1
Hrypa napisał(a):

Oczywiście, najlepiej to robić lokalnie. Ale nie zmusisz wszystkich deweloperów, żeby to robili. Jeżeli odpalisz unit testy dopiero na branchu integracyjnym i któryś test się wywali, trzeba będzie chwilę poszukać, który commit zepsuł test. Może to mimo wszystko lepsze podejście, ale jak napisałem, nie moja decyzja.

No chyba, że robimy build per commit, to nie trzeba niczego szukać.

Masz rację nie zmusisz ludzi do tego, aby nie byli niechlujni. Z drugiej strony, jak po zepsuciu testów dostaną parę razy karnego nosorożca, to może się nauczą porządku. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1