2011-01-07 13 views
9

Nasz zespół jest w trakcie łagodzenia TDD i zmagania się z najlepszymi praktykami w testach jednostkowych. Nasz testowany kod wykorzystuje wtrysk zależności. Nasze testy zazwyczaj podążają za układem Arrange-Act-Assert, gdzie kpimy z zależności w sekcji Rozmieść z Moq.Wielokrotne mocks vs kpiny w każdym teście

Teoretycznie testy jednostkowe powinny być tarczą, która chroni cię, jeśli byłaby. Ale staje się kotwicą, która nam to uniemożliwia. Próbuję ustalić, gdzie znajduje się nasza awaria procesowa.

Rozważmy uproszczony przykład:

  • XRepository.Save ma to podpis i zachowanie/kontrakt zmieniło.
  • XController.Save używa XRepository.Save, więc jest refaktoryzowany, aby korzystać z nowego interfejsu. Ale zewnętrznie kontrakt publiczny się nie zmienił.

Spodziewam się, że testy kontrolera zrobić nie należy refactored, ale zamiast udowodnić mi, że mój nowy kontroler wyróżnieniem wdrożeniowe niezmieniony kontrakt. Ale nie udało nam się tutaj, ponieważ tak nie jest.

Każdy test kontrolera wyśmiewa interfejs repozytorium w locie. Wszystkie one muszą zostać zmienione. Ponadto, ponieważ każdy test nie chce udawać wszystkich interfejsów i metod, nasz test jest związany z konkretną implementacją, ponieważ musi wiedzieć, jakie metody można kpić.

Stanie się trudniejsze do wykładania z wykładnikami, ponieważ mamy więcej testów! Lub dokładniej, tym więcej razy kpimy z interfejsu.

więc moje pytania:

  1. Wszelkie preferencji za korzystanie on-the-fly kpi w każdym teście vs dokonywania wielokrotnego użytku ręcznie wykonane makiety dla każdego interfejsu?

  2. Biorąc moja historia, jestem brakuje jakiegoś zasadę lub popadania Częstym błędem?

Dzięki!

+2

Ilekroć trzeba coś kpić, najpierw pomyśl, czy możesz tworzyć makiety ręcznie. Często odkrywasz, że sztuczki w locie zwykle dają zapach jawnej złożoności. Jeśli tak jest, to stwórz manuale ręczne, jeszcze inne w trybie "w locie" –

+1

Coś do rozważenia: http://en.wikipedia.org/wiki/Interface_segregation_principle – TrueWill

Odpowiedz

9

Nie można pominąć żadnej zasady, ale jest to powszechny problem. Myślę, że każda drużyna rozwiązuje (lub nie) na swój własny sposób.

Side Effects

Będzie nadal mają ten problem z dowolnej funkcji, która ma skutki uboczne. Znalazłem na bocznych funkcji efekt muszę zrobić testy, które zapewniają niektóre lub wszystkie z poniższych kryteriów:

  • , że był/nie był nazywany
  • Ile razy był nazywany
  • Jakie argumenty były przekazano mu
  • Kolejność połączeń.

Zapewnienie tego w teście oznacza zazwyczaj naruszenie hermetyzacji (interakcji i wiem z realizacją). Za każdym razem, gdy to zrobisz, zawsze domyślnie połączysz test z implementacją. To spowoduje, że będziesz musiał aktualizować test za każdym razem, gdy aktualizujesz porty implementacji, które wystawiasz/testujesz.

wielokrotnego użytku Mocks

Użyłem wielokrotnego mocks z dobrym skutkiem. Ich kompromis polega na tym, że ich wdrożenie jest bardziej złożone, ponieważ musi być bardziej kompletne. Uszczuplasz koszt aktualizacji testów, aby pomieścić refaktory.

Acceptance TDD

Inną opcją jest, aby zmienić swoje badania na. Ponieważ tak naprawdę chodzi o zmianę strategii testowania, nie jest to coś, z czym można się łatwo dostać. Najpierw możesz zrobić małą analizę i sprawdzić, czy rzeczywiście pasuje ona do twojej sytuacji.

Zwykłem robić TDD z testami jednostkowymi. Natknąłem się na kwestie, które uważałem, że nie powinniśmy mieć do czynienia. Zwłaszcza w odniesieniu do refaktorów zauważyłem, że zwykle musieliśmy aktualizować wiele testów. Te refaktory nie mieściły się w jednostce kodu, ale raczej w restrukturyzacji głównych komponentów. Wiem, że wiele osób powie, że problem polegał na częstych dużych zmianach, a nie na testach jednostkowych. Jest pewna prawda, że ​​duże zmiany są częściowo wynikiem naszego planowania/architektury. Jednak było to również z powodu decyzji biznesowych, które spowodowały zmiany w kierunkach. Te i inne uzasadnione przyczyny spowodowały konieczność wprowadzenia dużych zmian w kodzie. Rezultatem końcowym były duże refaktory, które stały się bardziej powolne i bolesne w wyniku wszystkich aktualizacji testów.

Wystąpiły również błędy z powodu problemów z integracją, których testy jednostkowe nie objęły. Zrobiliśmy kilka ręcznych testów akceptacyjnych. W rzeczywistości wykonaliśmy sporo pracy, aby testy akceptacyjne były jak najmniejsze. Nadal były ręczne i czuliśmy, że pomiędzy testami jednostkowymi a testem akceptacyjnym jest tak wiele przeniesienia, że ​​powinien istnieć sposób na złagodzenie kosztów wdrożenia obu.

Następnie firma miała zwolnienia. Nagle nie dysponowaliśmy taką samą ilością zasobów, które można było wykorzystać podczas programowania i konserwacji. Zostaliśmy popchnięci, aby uzyskać największy zwrot za wszystko, co zrobiliśmy, łącznie z testowaniem. Zaczęliśmy od dodania tzw. Testów na stosy częściowe w celu omówienia typowych problemów z integracją, które mieliśmy. Okazały się tak skuteczne, że zaczęliśmy robić mniej klasyczne testy jednostkowe. Pozbyliśmy się również ręcznych testów akceptacyjnych (Selenium). Powoli posunęliśmy się naprzód tam, gdzie testy zaczęły się testować, aż w zasadzie przeprowadziliśmy testy akceptacyjne, ale bez przeglądarki. Symulowalibyśmy metodę GET, POST lub PUT dla konkretnego kontrolera i sprawdzaliśmy kryteria akceptacji.

  • Baza danych została zaktualizowana poprawnie
  • Poprawny kod stanu HTTP został zwrócony
  • Strona została zwrócona, że:
    • był poprawny HTML 4.01 strict
    • zawierał informacje chcieliśmy wysłać z powrotem do użytkownika:

Zakończyliśmy posiadanie mniejszej ilości błędów. W szczególności prawie wszystkie błędy integracji i błędy spowodowane przez duże reaktory zniknęły prawie całkowicie.

Były kompromisy. Okazało się, że plusy znacznie przewyższają minusy. Minusy:

  • Test był zwykle bardziej skomplikowany i prawie każdy testował jakieś efekty uboczne.
  • Możemy stwierdzić, kiedy coś się zepsuje, ale nie jest tak ukierunkowane, jak testy jednostkowe, więc musimy zrobić więcej debugowania, aby znaleźć przyczynę problemu.
+0

Dzięki. Myślę, że zmierzamy w tym samym kierunku. Obecnie mamy testy integracyjne, które wychodzą z obiektów na poziomie domeny - nie posuwają się tak daleko, jak testowanie kontrolerów bezpośrednio. Kontrolery są nadal testowane przez kpiny z ich zależności. Dzięki za komentarze. –

1

Mam zmagał się z tego rodzaju wydać się i nie ma odpowiedzi, że czuję jest solidna, ale tutaj niepewny sposób myślenia. Obserwuję dwa rodzaje testów jednostkowych:

  1. Istnieją testy, w których należy korzystać z interfejsu publicznego, są one bardzo ważne, jeżeli mamy do czynienia z przekonaniem, udowadniają, że honorujemy naszą umowę z naszymi klientami. Testom tym najlepiej służy ręczna sztuczka wielokrotnego użytku, która zajmuje się niewielkim podzbiorem danych testowych.
  2. Istnieją testy "pokrycia". Są to zwykle dowody, że nasza implementacja zachowuje się poprawnie, gdy zależności źle się zachowują. Sądzę, że potrzebuję w locie szyderstw, aby sprowokować konkretne ścieżki realizacji.
+0

Dzięki za komentarz. Potwierdza niektóre z moich myśli. Myślę, że starałem się bardziej skupić na testach kontraktowych i myśleniu, czy ścieżka kodowa nie była częścią kontraktu, była zbędna. Ale może potrzebujemy być bardziej pragmatyczni. –

Powiązane problemy