Co to jest kpina?

Odpowiedzi:

598

Prolog: Jeśli spojrzeć na rzeczownik makiety w słowniku okaże się, że jedna z definicji tego słowa jest czymś wykonany jako imitację .


Wyśmiewanie jest stosowane głównie w testach jednostkowych. Testowany obiekt może być zależny od innych (złożonych) obiektów. Aby wyizolować zachowanie obiektu, należy zastąpić inne obiekty próbnymi symulacjami zachowania rzeczywistych obiektów. Jest to przydatne, jeśli rzeczywiste obiekty nie są praktyczne do włączenia do testu jednostkowego.

Krótko mówiąc, kpina to tworzenie obiektów symulujących zachowanie rzeczywistych obiektów.


Czasami może chcesz odróżnić wyśmianie w przeciwieństwie do stubbing . Być może istnieje pewien spór na ten temat, ale moja definicja odcinka jest „minimalnym” symulowanym obiektem. Kod pośredniczący implementuje zachowanie wystarczające, aby umożliwić testowanemu obiektowi wykonanie testu.

Makieta jest jak kod pośredniczący, ale test sprawdzi również, czy testowany obiekt wywołuje makietę zgodnie z oczekiwaniami. Część testu polega na sprawdzeniu, czy próbka została użyta poprawnie.

Podam przykład: możesz skasować bazę danych, wdrażając prostą strukturę pamięci do przechowywania rekordów. Testowany obiekt może następnie odczytywać i zapisywać rekordy w kodzie bazy danych, aby umożliwić mu wykonanie testu. Może to przetestować pewne zachowanie obiektu niezwiązanego z bazą danych, a kod pośredniczący bazy danych zostałby dołączony, aby umożliwić uruchomienie testu.

Jeśli zamiast tego chcesz sprawdzić, czy testowany obiekt zapisuje określone dane w bazie danych, będziesz musiał wyśmiewać bazę danych. Twój test obejmowałby następnie twierdzenia o tym, co zostało zapisane w makiecie bazy danych.

Martin Liversage
źródło
18
To dobra odpowiedź, ale niepotrzebnie ogranicza koncepcję kpiny do obiektów . Zastąpienie „obiektu” słowem „jednostka” uczyniłoby to bardziej ogólnym.
Rogério,
1
Rozumiem różnicę między skrótem a próbą. Jedyną rzeczą jest to, że jeśli testujesz swoje przypadki za pomocą kodu pośredniczącego, a on mija, to czy nie możesz stwierdzić, że już korzystasz z kodu pośredniczącego, a zatem nie potrzebujesz już weryfikacji ?
Honey,
91

Inne odpowiedzi wyjaśniają, czym jest drwina. Pozwól, że przeprowadzę cię przez różne przykłady . I uwierz mi, w rzeczywistości jest to o wiele prostsze niż myślisz.

tl; dr Jest to przykład oryginalnej klasy. Wprowadzono do niego inne dane, dzięki czemu unikniesz testowania wtryskiwanych części i skupisz się wyłącznie na testowaniu szczegółów implementacyjnych twojej klasy / funkcji.

Prosty przykład:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Jak widać, nie testuję LineA, tj. Nie sprawdzam poprawności parametrów wejściowych. Nie sprawdzam, czy num1, num2 są liczbami całkowitymi. Nie mam przeciwko temu żadnych zapewnień.

Testuję tylko, aby sprawdzić, czy LineB (moja implementacja ) poda wyśmiewane wartości 1i 5działa zgodnie z oczekiwaniami.

Oczywiście w prawdziwym słowie może to stać się znacznie bardziej złożone. Parametry mogą być niestandardowym obiektem, takim jak Osoba, Adres lub szczegóły implementacji mogą być więcej niż jednym +. Ale logika testowania byłaby taka sama.

Przykład niekodujący:

Załóżmy, że budujesz maszynę, która identyfikuje typ i markę urządzeń elektronicznych do ochrony lotniska. Maszyna robi to, przetwarzając to, co widzi za pomocą aparatu.

Teraz twój kierownik wchodzi do drzwi i prosi o przetestowanie ich w jednostce.

Następnie jako programista możesz przynieść 1000 prawdziwych obiektów, takich jak MacBook pro, Google Nexus, banan, iPad itp. I przetestować i sprawdzić, czy wszystko działa.

Ale możesz także użyć wyśmiewanych obiektów, takich jak identycznie wyglądający MacBook pro (bez prawdziwych części wewnętrznych) lub plastikowy banan przed nim. Możesz zaoszczędzić na inwestowaniu w 1000 prawdziwych laptopów i gnijących bananów.

Chodzi o to, że nie próbujesz sprawdzić, czy banan jest fałszywy, czy nie. Ani testowania, czy laptop jest fałszywy, czy nie. Wszystko robisz testuje jeśli urządzenie raz widzi banana byłoby powiedzieć, not an electronic devicea dla MacBooka Pro byłoby powiedzieć: Laptop, Apple. Dla maszyny wynik jego wykrycia powinien być taki sam dla fałszywej / wyśmiewanej elektroniki i prawdziwej elektroniki

Powyższa logika dotyczy również testowania jednostkowego rzeczywistego kodu. Ta funkcja powinna działać tak samo z rzeczywistymi wartościami uzyskanymi z rzeczywistych danych wejściowych (i interakcji) lub wyśmiewanymiwartości wprowadzane podczas testów jednostkowych. I podobnie jak oszczędzasz się przed używaniem prawdziwego banana lub MacBooka, dzięki testom jednostkowym (i kpinom) oszczędzasz siebie przed koniecznością zrobienia czegoś, co spowoduje, że Twój serwer zwróci kod statusu 500, 403, 200 itd. (Wymuszanie twój serwer wyzwala 500 tylko wtedy, gdy serwer jest wyłączony, a 200 gdy serwer jest włączony. Trudno jest uruchomić 100 testów sieciowych, jeśli musisz stale czekać 10 sekund między przełączaniem serwera w górę i w dół). Zamiast tego wstrzykujesz / wyśmiewasz odpowiedź kodem stanu 500, 200, 403 itd. I testujesz swoją jednostkę / funkcję za pomocą wstrzykniętej / wyśmiewanej wartości.

Przykład kodowania:

Powiedzmy, że piszesz aplikację na iOS i mają zadanie calls.Your sieć jest przetestować swoją aplikację. Testowanie / ustalanie, czy połączenia sieciowe działają zgodnie z oczekiwaniami, NIE JEST TO TWOJA ODPOWIEDZIALNOŚĆ. Testowanie go jest obowiązkiem innej strony (zespołu serwerów). Musisz usunąć tę zależność (sieciową), a mimo to kontynuować testowanie całego kodu, który działa wokół niej.

Połączenie sieciowe może zwrócić różne kody stanu 404, 500, 200, 303 itp. Z odpowiedzią JSON.

Twoja aplikacja powinna działać na wszystkie z nich (w przypadku błędów aplikacja powinna zgłosić oczekiwany błąd). To, co robisz z szyderstwem, to tworzenie „wymyślonych - podobnych do rzeczywistych” odpowiedzi sieciowych (takich jak kod 200 z plikiem JSON) i testowanie kodu bez „wykonywania prawdziwego połączenia sieciowego i oczekiwania na odpowiedź sieci”. Ręczne kodowanie / zwracanie odpowiedzi sieciowej dla WSZYSTKICH odpowiedzi sieciowych i sprawdzanie, czy aplikacja działa zgodnie z oczekiwaniami. (ty nigdy zakładać / przetestować 200 z błędnych danych, ponieważ to nie jest obowiązkiem, obowiązkiem jest, aby przetestować swoją aplikację z prawidłowym 200, lub w przypadku 400, 500, przetestować, czy aplikacja generuje właściwą błąd)

To tworzenie wymyślonego - podobnego do prawdziwego - nazywa się kpiną.

Aby to zrobić, nie możesz użyć oryginalnego kodu (oryginalny kod nie ma wstępnie wstawionych odpowiedzi, prawda?). Państwo musi dodać coś do niego, wstrzyknąć / wkładkę, która danych manekina, który normalnie nie jest potrzebne (lub część swojej klasie).

Więc utworzyć instancję oryginalnej klasy i dodać cokolwiek (tutaj jest sieć httpResponse, danych lub w przypadku awarii, przechodzą prawidłową errorString, httpResponse), należy do niego, a następnie przetestować szydzili klasę.

Krótko mówiąc, kpiny mają uprościć i ograniczyć to, co testujesz, a także nakarmić to, na czym polega klasa. W tym przykładzie unikają badania sieć nazywa się , a zamiast tego testu , czy aplikacja działa zgodnie z oczekiwaniami z wprowadzoną wyjść / odpowiedzi - przez wyśmianie klas

Nie trzeba dodawać, że każdą odpowiedź sieci testujesz osobno.


Teraz pytanie, które zawsze miałem na myśli, brzmiało: kontrakty / punkty końcowe i w zasadzie odpowiedź JSON moich API jest stale aktualizowana. Jak napisać testy jednostkowe, które biorą to pod uwagę?

Aby rozwinąć więcej na ten temat: powiedzmy, że model wymaga klucza / pola o nazwie username. Testujesz to, a test kończy się pomyślnie. 2 tygodnie później backend zmienia nazwę klucza na id. Twoje testy wciąż mija. dobrze? albo nie?

Czy to na deweloperze backendu spoczywa obowiązek aktualizowania próbnych wersji. Czy powinno być częścią naszej umowy, że dostarczają zaktualizowane symulacje?

Odpowiedzią na powyższy problem jest to, że: testy jednostkowe + proces programowania jako programista po stronie klienta powinien / będzie wychwytywać przestarzałe fałszywe odpowiedzi. Jeśli zapytasz mnie jak? odpowiedź brzmi:

Nasza rzeczywista aplikacja nie powiedzie się (lub nie zawiedzie, ale nie będzie miała pożądanego zachowania) bez użycia zaktualizowanych interfejsów API ... stąd jeśli to się nie powiedzie ... wprowadzimy zmiany w naszym kodzie programistycznym. Co ponownie prowadzi do niepowodzenia naszych testów ... które będziemy musieli poprawić. (W rzeczywistości, jeśli mamy poprawnie wykonać proces TDD, nie powinniśmy pisać żadnego kodu o polu, chyba że napiszemy test dla niego ... i zobaczymy, że się nie powiedzie, a następnie przejdziemy i napiszemy dla niego właściwy kod programistyczny.)

To wszystko oznacza, że ​​backend nie musi mówić: „hej, zaktualizowaliśmy kpiny” ... w końcu dzieje się to poprzez tworzenie / debugowanie kodu. ‌ّ Ponieważ to wszystko jest częścią procesu rozwoju! Chociaż jeśli backend zapewnia wyśmiewaną odpowiedź, jest to łatwiejsze.

Chodzi mi o to, że (jeśli nie możesz zautomatyzować pobierania zaktualizowanej fałszywej odpowiedzi API) wymagana jest interakcja człowieka, tj. Ręczne aktualizacje JSON i krótkie spotkania w celu upewnienia się, że ich wartości są aktualne, staną się częścią twojego procesu

Ta sekcja została napisana dzięki luźnej dyskusji w naszej grupie spotkań CocoaHead


Tylko dla deweloperów iOS:

Bardzo dobrym przykładem drwiny jest ta praktyczna zorientowana na protokół rozmowa Natashy Muraschev . Wystarczy przejść do minuty 18:30, chociaż slajdy mogą nie być zsynchronizowane z rzeczywistym filmem 🤷‍♂️

Bardzo podoba mi się ta część z transkrypcji:

Ponieważ to jest testowanie ... chcemy się upewnić, że getfunkcja z Gettablejest wywoływana, ponieważ może ona wrócić, a funkcja teoretycznie może przypisać tablicę artykułów spożywczych z dowolnego miejsca . Musimy się upewnić, że to się nazywa;

miód
źródło
3
Świetny przykład, chciałbym tylko dodać, że w tym konkretnym przykładzie podklasa działa jak próbka, ale w tym przykładzie również zastosowano stubowanie. Zakodowane odpowiedzi JSON są uważane za odpowiedzi pośrednie. Dodam to tylko dlatego, że rozróżnienie między próbkami i kodami pośredniczącymi może być trudne, ale ten przykład wyraźnie pokazuje, jak można używać obu razem.
user3344977
Doskonałe wyjaśnienie, dziękuję. Drobna poprawka do pytania o zmianę interfejsu API. Co jeśli nie jest to Twój interfejs API, więc nie jesteś częścią procesu programowania? Chcę wiedzieć, kiedy zawodzi moja biblioteka klienta.
ThinkDigital
@ThinkDigital Dostawcy dobrych interfejsów API mają dobre informacje o wersji i odpowiednio komunikują zmiany, jeśli nie masz tego kanału, być może nadszedł czas, abyś usiadł na spotkaniu i omówił go | dobrzy programiści zawsze sprawdzają zmiany interfejsu API nowej wersji i unikają jedynie aktualizacji wersji interfejsu API. Czy masz wersje API? Jeśli żadna z nich go nie złapie, to po sprawdzeniu jakości dowiesz się, a następnie zaktualizuj swoje testy ← obowiązek całego zespołu. → obowiązek jednego dewelopera: nie powinno go to obchodzić. Wystarczy obsłużyć przypadek, w którym serwer zwraca błąd lub serwer nie zwraca błędu, ale nie może parsować JSON lub obsłużyć poprawną wielkość liter.
Honey
Dzięki za odpowiedź, @ Kochanie! W moim przypadku utrzymuję klienta dla pub.dev , który ma API, ale poważnie go brakuje. Do tego stopnia, że ​​lepiej było stworzyć interfejs API poprzez zeskrobanie strony, niż użyć oficjalnego API. Z tego powodu zmiany w witrynie mogą uszkodzić kod i nie będą musiały niepokoić aktualizacji nikogo w tym przypadku. Witryna jest oprogramowaniem typu open source, ale inną rzeczą jest utrzymywanie interfejsu API opartego na zmianach wprowadzanych w bardziej trywialny sposób.
ThinkDigital
32

Istnieje wiele odpowiedzi na temat SO i dobrych postów w Internecie o kpinach. Jednym z miejsc, które warto zacząć, jest post Martina Fowlera Mocks Aren't Stubs, w którym omawia wiele pomysłów na kpiny.

W jednym akapicie - Kpina to jedna konkretna technika pozwalająca na testowanie jednostki kodu bez uzależnienia od zależności. Zasadniczo to, co odróżnia drwiny od innych metod, polega na tym, że fałszywe obiekty użyte do zastąpienia zależności kodu pozwolą na ustawienie oczekiwań - próbny obiekt będzie wiedział, jak ma być wywoływany przez twój kod i jak reagować.


Twoje pierwotne pytanie dotyczyło TypeMock, więc zostawiłem odpowiedź na to poniżej:

TypeMock to nazwa frameworku komercyjnego .

Oferuje wszystkie funkcje darmowych frameworków, takich jak RhinoMocks i Moq, a także kilka bardziej zaawansowanych opcji.

To, czy potrzebujesz TypeMock, jest wysoce dyskusyjne - możesz zrobić większość kpin, jakich kiedykolwiek chciałbyś, korzystając z bezpłatnych bibliotek kpin, a wielu twierdzi, że możliwości oferowane przez TypeMock często odciągają cię od dobrze zamkniętego projektu.

Jak wskazano w innej odpowiedzi, „TypeMocking” nie jest tak naprawdę zdefiniowaną koncepcją, ale może być rozumiany jako rodzaj kpin, jaki oferuje TypeMock, przy użyciu profilera CLR do przechwytywania wywołań .Net w czasie wykonywania, co daje znacznie większą zdolność do fałszowania obiektów (nie wymagań takich jak wymagające interfejsów lub metod wirtualnych).

David Hall
źródło
@Masoud nigdy nie wspominał o TypeMock. Jego pytanie dotyczyło ogólnie „kpin typu”.
Peter Lillevold
4
@Peter - jak powiedział inny komentarz, sprawdź historię edycji pytania. Niewiele mogę zrobić, jeśli opublikuję odpowiedź, a wtedy oryginalne pytanie zostanie całkowicie zmienione.
David Hall
9

Mock to metoda / obiekt symulujący zachowanie prawdziwej metody / obiektu w kontrolowany sposób. Próbne obiekty są używane w testach jednostkowych.

Często testowana metoda wywołuje inne usługi zewnętrzne lub metody w jej ramach. Są to tak zwane zależności. Po wyśmiewaniu zależności zachowują się tak, jak je zdefiniowaliśmy.

Z zależności kontrolowane przez symulacje, możemy łatwo przetestować zachowanie kodowanej przez nas metody. To jest testowanie jednostkowe.

Jaki jest cel fałszywych obiektów?

Makiety kontra odcinki

Testy jednostkowe a testy funkcjonalne

Venkat Kotra
źródło
7

Wyśmiewanie generuje pseudo-obiekty, które symulują zachowanie rzeczywistych obiektów na potrzeby testów

lol
źródło
5

Celem próbnych typów jest zerwanie zależności w celu odizolowania testu od konkretnej jednostki. Karczki są prostymi surogatami, zaś kpiny są surogatami, które mogą weryfikować użycie. Struktura próbna to narzędzie, które pomoże Ci wygenerować kody pośredniczące i próbne.

EDYCJA : Ponieważ oryginalne sformułowanie mówi o „kpinie typu”, mam wrażenie, że dotyczy to TypeMock. Z mojego doświadczenia wynika, że ​​ogólny termin to po prostu „kpina”. Możesz zignorować poniższe informacje, szczególnie w TypeMock.

TypeMock Isolator różni się od większości innych frameworków frameworkiem tym, że działa w trybie modyfikacji mojej IL. Pozwala to na kpowanie z typów i instancji, których większość innych frameworków nie może kpić. Aby wyśmiewać te typy / wystąpienia za pomocą innych frameworków, musisz dostarczyć własne abstrakcje i wyśmiewać je.

TypeMock oferuje dużą elastyczność kosztem czystego środowiska wykonawczego. Jako efekt uboczny sposobu, w jaki TypeMock osiąga wyniki, czasami uzyskuje się bardzo dziwne wyniki podczas korzystania z TypeMock.

Brian Rasmussen
źródło
@Masoud nigdy nie wspominał o TypeMock. Jego pytanie dotyczyło ogólnie „kpin typu”.
Peter Lillevold
1
@Peter: Oryginalne sformułowanie brzmiało „co to kpina z tekstu?”.
Brian Rasmussen
Wiem. Ponieważ „wyśmiewanie typów” nie jest równoważne z „TypeMock”, uważam, że zarówno twoja, jak i @Oded odpowiedź jest zupełnie inna.
Peter Lillevold
1
@Peter: Z mojego doświadczenia wynika, że ​​ogólny termin to „kpiny”, ale w każdym razie zaktualizowałem swoją odpowiedź, aby, mam nadzieję, wyjaśnić. Dzięki za wkład.
Brian Rasmussen
3

Wydaje mi się, że użycie frameworka izolującego TypeMock byłoby TypeMocking.

Jest to narzędzie, które generuje symulacje do użycia w testach jednostkowych, bez potrzeby pisania kodu z myślą o IoC.

Oded
źródło
@Masoud nigdy nie wspominał o TypeMock. Jego pytanie dotyczyło ogólnie „kpin typu”.
Peter Lillevold,
3
Właściwie pierwotne pytanie zawierało słowo „Type” przed „Mocking”, ale zostało później zredagowane. Dlatego niektóre odpowiedzi zawierają szczegółowe informacje o TypeMock.
Martin Liversage
1

Jeśli próbą jest żądanie sieciowe, inną alternatywą jest posiadanie prawdziwego serwera testowego. Możesz skorzystać z tej usługi, aby wygenerować żądanie i odpowiedź na potrzeby testowania. http://testerurl.com/

foobar8675
źródło
Właśnie próbowałem uzyskać do niego dostęp i zajęło to kilka minut. Kto może powiedzieć, że nie rejestruje też potajemnie żądań? Wreszcie może to być lepsze jako komentarz :)
Kieren Johnstone
Naprawdę go zdjąłem, ponieważ nie miałem ochoty przenieść go na bezpłatny hosting. tak, powinien to być komentarz. jest to oprogramowanie typu open source, więc jeśli istnieje obawa dotycząca rejestrowania żądań, możesz uruchomić własne. github.com/captainchung/TesterUrl
Matthew Chung,