Czy testy integracji (bazy danych) są złe?

120

Niektórzy twierdzą, że testy integracyjne są wszelkiego rodzaju złe i złe - wszystko musi być testowane jednostkowo, co oznacza, że ​​musisz kpić z zależności; opcja, która z różnych powodów nie zawsze mi się podoba.

Uważam, że w niektórych przypadkach test jednostkowy po prostu niczego nie dowodzi.

Jako przykład weźmy następującą (trywialną, naiwną) implementację repozytorium (w PHP):

class ProductRepository
{
    private $db;

    public function __construct(ConnectionInterface $db) {
        $this->db = $db;
    }

    public function findByKeyword($keyword) {
        // this might have a query builder, keyword processing, etc. - this is
        // a totally naive example just to illustrate the DB dependency, mkay?

        return $this->db->fetch("SELECT * FROM products p"
            . " WHERE p.name LIKE :keyword", ['keyword' => $keyword]);
    }
}

Powiedzmy, że chcę udowodnić w teście, że to repozytorium może faktycznie znaleźć produkty pasujące do różnych podanych słów kluczowych.

Bez testowania integracji z rzeczywistym obiektem połączenia, skąd mam wiedzieć, że generuje to prawdziwe zapytania - i że te zapytania faktycznie robią to, co myślę?

Jeśli muszę kpić z obiektu połączenia w teście jednostkowym, mogę tylko udowodnić, że „generuje oczekiwane zapytanie” - ale to nie znaczy, że faktycznie zadziała ... to znaczy, może generuje zapytanie Spodziewałem się, ale może to zapytanie nie robi tego, co myślę, że działa.

Innymi słowy, czuję się jak test, który wysuwa twierdzenia na temat wygenerowanego zapytania, jest w zasadzie bez wartości, ponieważ testuje sposób implementacjifindByKeyword() metody , ale to nie dowodzi, że faktycznie działa .

Ten problem nie ogranicza się do repozytoriów lub integracji bazy danych - wydaje się, że ma zastosowanie w wielu przypadkach, w których stwierdzenia dotyczące użycia próbnego (podwójnego testu) tylko dowodzą, jak rzeczy są realizowane, a nie czy zamierzają faktycznie działa.

Jak sobie radzisz w takich sytuacjach?

Czy testy integracyjne są naprawdę „złe” w takim przypadku?

Rozumiem, że lepiej przetestować jedną rzecz, a także rozumiem, dlaczego testowanie integracji prowadzi do niezliczonych ścieżek kodu, z których wszystkie nie mogą być testowane - ale w przypadku usługi (takiej jak repozytorium), której jedynym celem jest w celu interakcji z innym komponentem, w jaki sposób można naprawdę przetestować coś bez testowania integracji?

mindplay.dk
źródło
5
Przeczytaj agitar.com/downloads/TheWayOfTestivus.pdf , zwłaszcza strona 6 „Test jest ważniejszy niż jednostka”.
Doc Brown,
2
@ user61852 w opisie jest napisane „naiwny”, tak?
mindplay.dk
4
Jak twój współpracownik byłby absolutnie pewien, że jego szydercza baza danych zachowuje się jak prawdziwa?
Thorbjørn Ravn Andersen
12
Starasz się być realistą. Twój współpracownik stara się przestrzegać zasad. Zawsze pisz testy, które wytwarzają wartość . Nie marnuj czasu na pisanie testów, które będą nie do pomalowania, i nie pisz testów, które nie wykonują żadnej z poniższych czynności: zwiększ prawdopodobieństwo, że Twój kod jest poprawny lub zmuś do napisania bardziej łatwego do utrzymania kodu.
jpmc26
3
@ mindplay.dk: kluczowe zdanie w tym akapicie brzmi: „Ale nie utknij na żadnym dogmacie. Napisz test, który należy napisać.” Twój współpracownik wydaje się utknąć w dogmacie. I nie potrzebujesz kogoś wyjaśniając, jaki jest test, który należy napisać w twoim przykładzie - już to wiesz. Jest całkiem oczywiste, że do testowania, czy twoja baza danych rozumie zapytanie, musisz uruchomić zapytanie w stosunku do prawdziwej bazy danych - żadna próbna informacja nie może ci powiedzieć to
Doc Brown

Odpowiedzi:

129

Twój współpracownik ma rację, że wszystko, co może być testowane jednostkowo, powinno być testowane jednostkowo, i masz rację, że testy jednostkowe zabiorą cię tylko tak daleko i nie dalej, szczególnie podczas pisania prostych opakowań wokół złożonych usług zewnętrznych.

Powszechnym sposobem myślenia o testowaniu jest piramida testowa . Jest to koncepcja często związana z Agile i wiele o niej pisało, w tym Martin Fowler (który przypisuje ją Mike'owi Cohnowi w „ Sukcesie z Agile” ), Alistair Scott i Blog testowy Google .

        /\                           --------------
       /  \        UI / End-to-End    \          /
      /----\                           \--------/
     /      \     Integration/System    \      /
    /--------\                           \----/
   /          \          Unit             \  /
  --------------                           \/
  Pyramid (good)                   Ice cream cone (bad)

Chodzi o to, że szybkie, odporne testy jednostkowe są podstawą procesu testowania - powinny być bardziej ukierunkowane testy jednostkowe niż testy systemowe / integracyjne, a więcej testów systemowych / integracyjnych niż testy kompleksowe. W miarę zbliżania się do szczytu testy zwykle wymagają więcej czasu / zasobów, poddawane są kruchości i kruchości, a także mniej precyzyjne określanie, który system lub plik jest uszkodzony ; naturalnie lepiej jest unikać bycia „ciężkim”.

Do tego momentu testy integracyjne nie są złe , ale duże poleganie na nich może wskazywać, że nie zaprojektowałeś poszczególnych komponentów, aby były łatwe do przetestowania. Pamiętaj, że celem jest sprawdzenie, czy Twoja jednostka działa zgodnie ze specyfikacją, przy minimalnej liczbie innych systemów łamliwych : możesz wypróbować bazę danych w pamięci (którą liczę jako test przyjazny dla jednostki podwójnie obok prób ), na przykład w przypadku ciężkich testów skrajnych przypadków, a następnie napisz kilka testów integracyjnych z prawdziwym silnikiem bazy danych, aby ustalić, że główne przypadki działają podczas montażu systemu.


Na marginesie wspomniałeś, że pisane przez ciebie makiety po prostu sprawdzają, jak coś jest implementowane, a nie czy to działa . To coś w rodzaju antypatternu: test, który jest idealnym odzwierciedleniem jego implementacji, tak naprawdę wcale nie testuje. Zamiast tego sprawdź, czy każda klasa lub metoda zachowuje się zgodnie z własną specyfikacją , na dowolnym wymaganym poziomie abstrakcji lub realizmu.

Jeff Bowman
źródło
13
+1 za „Test, który jest idealnym odzwierciedleniem jego implementacji, tak naprawdę wcale nie testuje”. Zbyt często. Nazywam to Antypatternem Doppelgangera .
dodgethesteamroller
6
Kontrowersyjna szkoła QA oprogramowania, kontekstowego ruchu testowego , jest częściowo poświęcona sporom, że istnieją tak przydatne ogólne zasady, jak Piramida Testowa. W szczególności, przełomowe teksty tego ruchu podają wiele przykładów, w których testy integracyjne są znacznie cenniejsze niż inne rodzaje testów (ponieważ testują system w kontekście, jako system ) ....
dodgethesteamroller
7
... w konsekwencji Fowler i wsp., argumentując, że należy poświęcić mniej wysiłku na testy integracyjne i testy akceptacji użytkownika, ponieważ są zbyt trudne do napisania w solidny i łatwy do utrzymania sposób, naprawdę stanowią po prostu usprawiedliwienie ex post dla uzasadnienia oni nie zorientowali się, jak dobrze przetestować na wyższych poziomach.
dodgethesteamroller
1
@dodgethesteamroller Dogłębne dyskusje na temat „szkoły contrarian” najlepiej pasują do własnej odpowiedzi. Osobiście uważam, że blog Testing Google robi bardzo dobrą robotę opisujące zalety szybkich, mocno o zakresie zautomatyzowanych testów obok testów System-in-kontekstu. Jeśli okaże się, że jest niejasne, wymieniam tutaj piramidę testową jako przydatny model lub punkt wyjścia, a nie jako wymówkę, aby przestać myśleć jako inżynier.
Jeff Bowman,
1
Wysoce zalecana prezentacja na temat hierarchii i stosunku jednostek testowych do testów integracyjnych: vimeo.com/80533536 Bardzo dobrze wyjaśnione.
szalski
88

Jeden z moich współpracowników twierdzi, że testy integracyjne są wszelkiego rodzaju złe i złe - wszystko musi być testowane jednostkowo,

To trochę jak powiedzenie, że antybiotyki są złe - wszystko należy wyleczyć za pomocą witamin.

Testy jednostkowe nie wychwytują wszystkiego - testują jedynie działanie komponentu w kontrolowanym środowisku . Testy integracyjne sprawdzają, czy wszystko działa razem , co jest trudniejsze, ale w końcu bardziej znaczące.

Dobry, kompleksowy proces testowania wykorzystuje oba typy testów - testy jednostkowe w celu weryfikacji reguł biznesowych i innych rzeczy, które mogą być testowane niezależnie, oraz testy integracyjne, aby upewnić się, że wszystko działa razem.

Bez testowania integracji z rzeczywistym obiektem połączenia, skąd mam wiedzieć, że generuje to prawdziwe zapytania - i że te zapytania faktycznie robią to, co myślę?

Państwo mogłoby jednostka przetestować go na poziomie bazy danych . Uruchom zapytanie z różnymi parametrami i sprawdź, czy uzyskasz oczekiwane wyniki. Oczywiście oznacza to kopiowanie / wklejanie wszelkich zmian z powrotem do „prawdziwego” kodu. ale to nie pozwalają, aby przetestować niezależnie zapytania wszelkich innych zależności.

D Stanley
źródło
Czy nie testowałbyś, czy baza danych zawiera określone dane?
Tulains Córdova,
Być może - ale możesz również testować, czy działają Twoje filtry, złożone sprzężenia itp. Przykładowa kwerenda prawdopodobnie nie jest najlepszym kandydatem do „testów jednostkowych”, ale może zawierać złożone sprzężenia i / lub agregacje.
D Stanley,
Tak - jak wskazałem, przykład, którego użyłem, jest trywialny; prawdziwe repozytorium może mieć wszystkie złożone opcje wyszukiwania i sortowania, np. za pomocą konstruktora zapytań itp.
mindplay.dk
2
Dobra odpowiedź, ale dodam, że DB powinien być w pamięci, aby upewnić się, że testy jednostkowe są szybkie.
BЈовић
3
@ BЈовић: Niestety, nie zawsze może to być możliwe, ponieważ niestety nie ma dwóch kompatybilnych DB i nie wszystkie działają w pamięci. Istnieją również problemy z licencjonowaniem komercyjnych baz danych (możesz nie mieć licencji, aby uruchomić ją na dowolnym komputerze), ...
Matthieu M.,
17

Testy jednostkowe nie wychwytują wszystkich wad. Są jednak tańsze w konfiguracji i (ponownym) uruchamianiu w porównaniu z innymi rodzajami testów. Testy jednostkowe są uzasadnione przez połączenie umiarkowanej wartości i niskich do umiarkowanych kosztów.

Oto tabela przedstawiająca wskaźniki wykrywania defektów dla różnych rodzajów testów.

wprowadź opis zdjęcia tutaj

źródło: str.470 w Code Complete 2 autorstwa McConnell

Nick Alexeev
źródło
5
Dane te zostały zebrane w 1986 r . To było trzydzieści lat temu . Testy jednostkowe w 1986 r. Nie były tym, czym są dzisiaj. Byłbym sceptycznie nastawiony do tych danych. Nie wspominając o tym, że testy jednostkowe wykrywają błąd przed jego popełnieniem , więc wątpliwe jest, aby został zgłoszony.
RubberDuck,
3
@RubberDuck Ten wykres pochodzi z książki z 2006 roku i jest oparty na danych z 1986, 1996, 2002 (jeśli przyjrzysz się uważnie). Nie sprawdziłem protokołów gromadzenia danych w źródłach, nie mogę powiedzieć, kiedy zaczęły śledzić defekt i jak zostało zgłoszone. Czy ten wykres może być nieco nieaktualny? To mogło. W grudniu byłem na seminarium, a instruktor wspomniał, że testy integracyjne wykrywają więcej błędów niż testy jednostkowe (2 razy, iirc). Ta tabela mówi, że są mniej więcej takie same.
Nick Alexeev
13

Nie, nie są złe. Mamy nadzieję, że należy przeprowadzić testy jednostkowe i integracyjne. Są używane i działają na różnych etapach cyklu rozwoju.

Testy jednostkowe

Testy jednostkowe powinny być uruchamiane na serwerze kompilacji i lokalnie, po skompilowaniu kodu. Jeśli jakiekolwiek testy jednostkowe zakończą się niepowodzeniem, należy zakończyć kompilację lub nie zatwierdzić aktualizacji kodu, dopóki testy nie zostaną naprawione. Powodem, dla którego chcemy izolować testy jednostkowe, jest to, że chcemy, aby serwer kompilacji mógł uruchamiać wszystkie testy bez wszystkich zależności. Następnie moglibyśmy uruchomić kompilację bez wszystkich wymaganych wymaganych zależności i przeprowadzić wiele testów, które działają bardzo szybko.

Tak więc w przypadku bazy danych należy mieć coś takiego:

IRespository

List<Product> GetProducts<String Size, String Color);

Teraz rzeczywista implementacja IRepository trafi do bazy danych, aby uzyskać produkty, ale w celu przeprowadzenia testów jednostkowych można wyśmiewać IRepository z fałszywym, aby uruchomić wszystkie testy w razie potrzeby bez bazy danych Actaul, ponieważ możemy symulować wszelkiego rodzaju listy produktów są zwracane z fałszywej instancji i testują dowolną logikę biznesową z fałszywymi danymi.

Testy integracyjne

Testy integracyjne są zazwyczaj testami przekraczania granic. Chcemy uruchamiać te testy na serwerze wdrażania (prawdziwe środowisko), piaskownicy, a nawet lokalnie (wskazane na piaskownicy). Nie są uruchamiane na serwerze kompilacji. Po wdrożeniu oprogramowania w środowisku zwykle będą one uruchamiane jako działania po wdrożeniu. Można je zautomatyzować za pomocą narzędzi wiersza poleceń. Na przykład możemy uruchomić nUnit z wiersza poleceń, jeśli podzielimy na kategorie wszystkie testy integracyjne, które chcemy wywołać. W rzeczywistości wywołują one prawdziwe repozytorium z prawdziwym wywołaniem bazy danych. Tego typu testy pomagają w:

  • Środowisko Zdrowie Stabilność Gotowość
  • Testowanie prawdziwej rzeczy

Testy te są czasem trudniejsze do przeprowadzenia, ponieważ może być konieczne ustawienie i / lub zburzenie. Rozważ dodanie produktu. Prawdopodobnie chcemy dodać produkt, zapytać go, czy został dodany, a następnie po zakończeniu usunąć go. Nie chcemy dodawać setek lub tysięcy produktów „integracyjnych”, dlatego wymagana jest dodatkowa konfiguracja.

Testy integracyjne mogą okazać się bardzo cenne przy sprawdzaniu poprawności środowiska i upewnieniu się, że działa.

Trzeba mieć oba.

  • Uruchom testy jednostkowe dla każdej kompilacji.
  • Przeprowadź testy integracyjne dla każdego wdrożenia.
Jon Raynor
źródło
Zalecałbym przeprowadzanie testów integracyjnych dla każdej kompilacji zamiast konieczności zatwierdzania i wypychania. Zależy od tego, jak długo to potrwa, ale dobrym pomysłem jest też utrzymywanie ich z wielu powodów.
artbristol
@ArtBristol - Zazwyczaj nasz serwer kompilacji nie ma skonfigurowanej pełnej zależności środowiska, więc nie możemy tam uruchomić naszych testów integracyjnych. Ale jeśli można tam uruchomić testy integracji, idź. Mamy piaskownicę wdrażania skonfigurowaną po kompilacji, której używamy do testowania integracji w celu weryfikacji wdrożenia. Ale każda sytuacja jest inna.
Jon Raynor
11

Testy integracji bazy danych nie są złe. Co więcej, są one konieczne.

Prawdopodobnie masz aplikację podzieloną na warstwy, i to dobrze. Możesz przetestować każdą warstwę w izolacji, wyśmiewając sąsiednie warstwy, i to też dobrze. Ale bez względu na to, ile warstw abstrakcji utworzysz, w pewnym momencie musi być warstwa, która wykonuje brudną robotę - faktycznie rozmawia z bazą danych. O ile go nie przetestujesz, w ogóle go nie testujesz. Jeśli testujesz warstwę n przez kpinę z warstwy n-1, oceniasz założenie, że warstwa n działa pod warunkiem, że warstwa n-1 działa. Aby to zadziałało, musisz jakoś udowodnić, że warstwa 0 działa.

Podczas gdy teoretycznie możesz testować bazę danych, analizując i interpretując wygenerowany SQL, o wiele łatwiej i pewniej jest stworzyć testową bazę danych w locie i z nią porozmawiać.

Wniosek

Jaka jest pewność, jaką wzbudza jednostka testująca twoje repozytorium abstrakcyjne , Ethereal Object-Relational-Mapper , Generic Active Record , Theoretic Persistence layer, kiedy ostatecznie wygenerowany SQL zawiera błąd składniowy?

el.pescado
źródło
Myślałem o dodaniu odpowiedzi podobnej do twojej, ale powiedziałeś to lepiej! Z mojego doświadczenia, że ​​kilka testów na warstwie, która pobiera i przechowuje dane, zaoszczędziło mi wiele smutku.
Daniel Hollinrake
Testy integracji bazy danych są jednak złe. Czy masz bazę danych dostępną w linii ci / cd? Wydaje mi się to dość skomplikowane. O wiele łatwiej jest kpić z bazy danych i zbudować warstwę abstrakcji, aby z niej skorzystać. Jest to nie tylko znacznie bardziej eleganckie rozwiązanie, ale jest tak szybkie, jak to tylko możliwe. Testy jednostkowe muszą być szybkie. Testowanie bazy danych znacznie spowalnia twoje unittesty do poziomu, który jest niedopuszczalny. Unittests nie powinno zająć więcej niż 10 minut, nawet jeśli masz ich tysiące.
David
@David Czy masz bazę danych dostępną w linii ci / cd? Jasne, to dość standardowa funkcja . BTW, nie zalecam testów integracyjnych zamiast testów jednostkowych - zalecam testy integracyjne w połączeniu z testami jednostkowymi. Szybkie testy jednostkowe są niezbędne, ale bazy danych są zbyt złożone, aby polegać na testach jednostkowych z udawanymi interakcjami.
el.pescado,
@ el.pescado Muszę się nie zgodzić. Jeśli komunikacja w bazie danych kryje się za warstwą abstrakcji, naprawdę łatwo jest wyśmiewać. Możesz po prostu zdecydować, który obiekt zwrócić. Ponadto fakt, że coś jest standardem, nie czyni z niego nic dobrego.
David
@David Myślę, że to zależy od tego, jak podejdziesz do bazy danych. Czy to szczegół implementacji, czy istotna część systemu ? (Pochylam się w kierunku tego drugiego) . Jeśli traktujesz bazę danych jako głupie przechowywanie danych, to tak, możesz zrobić bez testów integracyjnych. Jednak jeśli w bazie danych jest jakaś logika - ograniczenia, wyzwalacze, klucze obce, transakcje lub twoja warstwa danych używa niestandardowego SQL zamiast zwykłych metod ORM, uważam, że same testy jednostkowe nie wystarczą.
el.pescado,
6

Potrzebujesz obu.

W twoim przykładzie, jeśli testujesz bazę danych w określonych warunkach, po uruchomieniu findByKeywordmetody otrzymasz dane z powrotem, oczekujesz, że jest to dobry test integracji.

W każdym innym kodzie używającym tej findByKeywordmetody chcesz kontrolować, co jest wprowadzane do testu, abyś mógł zwrócić wartości null lub odpowiednie słowa do testu, czy cokolwiek wtedy kpisz z zależności bazy danych, abyś dokładnie wiedział, co będzie w teście odbierać (i tracisz narzut związany z połączeniem z bazą danych i upewnieniem się, że dane w niej są poprawne)

Froome
źródło
6

Autor artykułu na blogu, do którego się odwołujesz, zajmuje się głównie potencjalną złożonością, która może wynikać ze zintegrowanych testów (chociaż jest napisana w bardzo opiniotwórczy i kategoryczny sposób). Jednak testy zintegrowane niekoniecznie są złe, a niektóre z nich są bardziej przydatne niż testy jednostkowe. To zależy od kontekstu twojej aplikacji i tego, co próbujesz przetestować.

Wiele dzisiejszych aplikacji po prostu nie działałoby, gdyby ich serwer bazy danych przestał działać. Pomyśl o tym przynajmniej w kontekście funkcji, którą próbujesz przetestować.

Z jednej strony, jeśli to, co próbujesz przetestować, nie zależy od bazy danych, lub możesz sprawić, że w ogóle nie będzie zależało, to napisz test w taki sposób, aby nawet nie próbował użyć baza danych (wystarczy podać fałszywe dane zgodnie z wymaganiami). Na przykład, jeśli próbujesz przetestować logikę uwierzytelniania podczas udostępniania strony internetowej (na przykład), prawdopodobnie dobrze jest całkowicie odłączyć ją od bazy danych (zakładając, że nie polegasz na bazie danych do uwierzytelniania, lub że możesz łatwo z niego kpić).

Z drugiej strony, jeśli jest to funkcja, która jest bezpośrednio zależna od bazy danych i która w ogóle nie działałaby w prawdziwym środowisku, gdyby baza danych była niedostępna, to kpiąc sobie z tego, co DB robi w kodzie klienta DB (tj. Z warstwy używającej tego DB) niekoniecznie ma sens.

Na przykład, jeśli wiesz, że twoja aplikacja będzie polegać na bazie danych (i być może na konkretnym systemie baz danych), kpowanie ze zachowania bazy danych ze względu na to często będzie stratą czasu. Silniki baz danych (zwłaszcza RDBMS) są złożonymi systemami. Kilka wierszy SQL może faktycznie wykonać wiele pracy, co byłoby trudne do symulacji (w rzeczywistości, jeśli zapytanie SQL ma kilka wierszy, istnieje szansa, że ​​będziesz potrzebował znacznie więcej wierszy Java / PHP / C # / Python kod do wygenerowania tego samego wyniku wewnętrznie): powielanie logiki, którą już zaimplementowałeś w DB, nie ma sensu, a sprawdzenie tego kodu testowego stałoby się problemem samo w sobie.

Niekoniecznie traktowałbym to jako problem testu jednostkowego w porównaniu z testem zintegrowanym , ale raczej patrzę na zakres tego, co jest testowane. Pozostają ogólne problemy z testowaniem jednostkowym i integracyjnym: potrzebujesz rozsądnie realistycznego zestawu danych testowych i przypadków testowych, ale coś, co jest również wystarczająco małe, aby testy mogły zostać wykonane szybko.

Czas na zresetowanie bazy danych i ponowne wypełnienie danymi testowymi jest aspektem do rozważenia; ogólnie oceniasz to w stosunku do czasu, jaki zajmuje napisanie tego fałszywego kodu (który ostatecznie będziesz musiał zachować).

Inną kwestią do rozważenia jest stopień zależności aplikacji od bazy danych.

  • Jeśli twoja aplikacja po prostu działa zgodnie z modelem CRUD, w którym masz warstwę abstrakcji, która pozwala przełączać się między dowolnym RDBMS za pomocą prostych ustawień konfiguracyjnych, istnieje szansa, że ​​będziesz w stanie dość łatwo pracować z fałszywym systemem (możliwe rozmycie linia między testowaniem jednostkowym a zintegrowanym za pomocą RDBMS w pamięci).
  • Jeśli twoja aplikacja używa bardziej złożonej logiki, coś, co byłoby specyficzne dla jednego z SQL Server, MySQL, PostgreSQL (na przykład), wtedy ogólnie sensowniej byłoby mieć test, który używa tego konkretnego systemu.
Bruno
źródło
„Wiele dzisiejszych aplikacji po prostu nie działałoby, gdyby ich serwer bazy danych przestał działać” - to naprawdę ważny punkt!
el.pescado,
Dobre wyjaśnienie ograniczeń złożonych prób, na przykład użycie innego języka do kpienia z SQL. Kiedy kod testowy staje się na tyle skomplikowany, że wydaje się, że należy go przetestować, to jest to zapach QA.
dodgethesteamroller
1

Masz rację, że taki test jednostkowy jest niekompletny. Niekompletność polega na wyśmiewaniu interfejsu bazy danych. Oczekiwania lub twierdzenia naiwnego kpiny są niepełne.

Aby go ukończyć, musisz poświęcić wystarczająco dużo czasu i zasobów, aby napisać lub zintegrować silnik reguł SQL, który zagwarantuje, że instrukcja SQL emitowana przez badany podmiot spowoduje oczekiwane operacje.

Jednak często zapomnianą i nieco kosztowną alternatywą / towarzyszem kpin jest „wirtualizacja” .

Czy potrafisz rozpakować tymczasową instancję DB w pamięci, ale „prawdziwą”, do testowania pojedynczej funkcji? tak ? tam masz lepszy test, ten, który sprawdza rzeczywiste dane zapisane i odzyskane.

Można powiedzieć, że zamieniłeś test jednostkowy w test integracyjny. Istnieją różne poglądy na temat tego, gdzie należy wyznaczyć linię do klasyfikowania między testami jednostkowymi a testami integracji. IMHO, „jednostka” jest dowolną definicją i powinna pasować do twoich potrzeb.

SD
źródło
1
wydaje się to jedynie powtórzyć uwagi przedstawione i wyjaśnione w poprzedniej odpowiedzi, która została opublikowana kilka godzin temu
gnat
0

Unit Testsi Integration Testssą do siebie prostopadłe . Oferują one inne spojrzenie na budowaną aplikację. Zwykle chcesz obu . Ale moment w czasie jest inny, kiedy chcesz, jakiego rodzaju testy.

Najczęściej chcesz Unit Tests. Testy jednostkowe koncentrują się na niewielkiej części testowanego kodu - unitczytelnikowi pozostaje dokładnie to, co nazywa się a . Ale cel jest prosty: uzyskiwanie szybkiej informacji zwrotnej o tym, kiedy i gdzie pękł kod . Powiedział, że powinno być jasne, że wzywa do rzeczywistej DB jest nono .

Z drugiej strony istnieją rzeczy, które mogą być testowane jednostkowo tylko w trudnych warunkach bez bazy danych. Być może w twoim kodzie jest warunek wyścigu, a wywołanie DB powoduje naruszenie, unique constraintktóre może zostać rzucone tylko wtedy, gdy faktycznie używasz swojego systemu. Ale tego rodzaju testy są drogie , których nie możesz (i nie chcesz) uruchamiać tak często, jak unit tests.

Thomas Junk
źródło
0

W świecie .Net mam zwyczaj tworzenia projektu testowego i tworzenia testów jako metody kodowania / debugowania / testowania w obie strony minus interfejs użytkownika. To dla mnie skuteczny sposób na rozwój. Nie byłem tak zainteresowany przeprowadzaniem wszystkich testów dla każdej kompilacji (ponieważ spowalnia to moje prace rozwojowe), ale rozumiem przydatność tego dla większego zespołu. Niemniej jednak można wprowadzić regułę, zgodnie z którą przed zatwierdzeniem kodu wszystkie testy powinny zostać uruchomione i zdane (jeśli uruchomienie testów potrwa dłużej, ponieważ baza danych jest faktycznie atakowana).

Wyśmiewanie warstwy dostępu do danych (DAO) i nie trafianie do bazy danych, nie tylko nie pozwala mi kodować w sposób, w jaki lubię i przyzwyczaiłem się, ale brakuje dużej części rzeczywistej bazy kodu. Jeśli tak naprawdę nie testujesz warstwy dostępu do danych i bazy danych i po prostu udajesz, a następnie spędzasz dużo czasu na wyśmiewaniu się, nie rozumiem przydatności tego podejścia do testowania mojego kodu. Testuję mały kawałek zamiast większego za pomocą jednego testu. Rozumiem, że moje podejście może być bardziej zgodne z testem integracyjnym, ale wydaje się, że test jednostkowy z próbą jest zbędną stratą czasu, jeśli faktycznie napisasz test integracyjny raz i pierwszy. To także dobry sposób na rozwijanie i debugowanie.

W rzeczywistości od jakiegoś czasu zdaję sobie sprawę z TDD i Behaviour Driven Design (BDD) i zastanawiam się, jak go użyć, ale trudno jest dodać testy jednostkowe z mocą wsteczną. Być może się mylę, ale napisanie testu, który obejmuje więcej kodów od końca do końca z dołączoną bazą danych, wydaje się być o wiele bardziej kompletnym testem o wyższym priorytecie, który obejmuje więcej kodów i jest bardziej wydajnym sposobem pisania testów.

W rzeczywistości uważam, że coś takiego jak Behaviour Driven Design (BDD), które próbuje przetestować od końca do końca w języku specyficznym dla domeny (DSL), powinno być dobrym rozwiązaniem. Mamy SpecFlow w .Net świecie, ale zaczął się jako open source z Cucumber.

https://cucumber.io/

Po prostu nie jestem pod wrażeniem prawdziwej użyteczności testu, który napisałem, wyśmiewając warstwę dostępu do danych i nie uderzając w bazę danych. Zwrócony obiekt nie trafił do bazy danych i nie został wypełniony danymi. Był to całkowicie pusty przedmiot, który musiałem kpić w nienaturalny sposób. Myślę, że to strata czasu.

Zgodnie z przepełnieniem stosu kpina jest stosowana, gdy rzeczywiste obiekty są niepraktyczne do włączenia do testu jednostkowego.

https://stackoverflow.com/questions/2665812/what-is-mocking

„Wyśmiewanie jest stosowane przede wszystkim w testach jednostkowych. Testowany obiekt może być zależny od innych (złożonych) obiektów. Aby wyizolować zachowanie obiektu, który chcesz przetestować, zastąp 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. ”

Moim argumentem jest to, że jeśli koduję coś od końca do końca (interfejs WWW do warstwy biznesowej do warstwy dostępu do danych do bazy danych, podróż w obie strony), zanim zarejestruję coś jako programista, przetestuję ten przepływ w obie strony. Jeśli wycinę interfejs użytkownika i debuguję i przetestuję ten przepływ, zaczynając od testu, testuję wszystko poza interfejsem użytkownika i zwracam dokładnie to, czego oczekuje interfejs użytkownika. Pozostało mi tylko wysłać interfejs użytkownika, czego chce.

Mam bardziej kompletny test, który jest częścią mojego naturalnego procesu rozwoju. Dla mnie powinien to być test o najwyższym priorytecie, który obejmuje testowanie rzeczywistej specyfikacji użytkownika w jak największym stopniu. Jeśli nigdy nie utworzę żadnych bardziej szczegółowych testów, przynajmniej mam ten jeden pełny test, który dowodzi, że moja pożądana funkcjonalność działa.

Współzałożyciel Stack Exchange nie jest przekonany o zaletach posiadania 100% pokrycia testem jednostkowym. Ja też nie jestem. Zrobiłbym bardziej kompletny „test integracyjny”, który uderzył w bazę danych, utrzymując kilka próbnych baz danych każdego dnia.

https://www.joelonsoftware.com/2009/01/31/from-podcast-38/

użytkownik3198764
źródło
jest tak oczywiste, że nie rozumiesz różnicy między testami jednostkowymi a integracyjnymi
BЈовић
Myślę, że to zależy od projektu. W mniejszych projektach z mniejszą ilością zasobów, w których programista jest bardziej ogólnie odpowiedzialny za testowanie i testowanie regresyjne z powodu braku testerów i synchronizacji dokumentacji z kodem, jeśli zamierzam poświęcić trochę czasu na pisanie testów, będą to takie, które daje mi największy huk za moją złotówkę. Chcę zabić jak najwięcej ptaków jednym kamieniem, jak to możliwe. Jeśli większość mojej logiki i błędów pochodzi z procedur przechowywanych w bazie danych, które generują raporty, lub z frontonu JavaScript, posiadanie pełnego pokrycia testów jednostkowych na środkowej warstwie niewiele pomaga.
user3198764,
-1

Zależności zewnętrzne powinny być wyśmiewane, ponieważ nie można ich kontrolować (mogą przejść przez fazę testów integracyjnych, ale zawiodą w produkcji). Dyski mogą ulec awarii, połączenia z bazą danych mogą się nie powieść z wielu powodów, mogą wystąpić problemy z siecią itp. Testy integracyjne nie dają żadnej dodatkowej pewności, ponieważ wszystkie one mogą wystąpić w czasie wykonywania.

Dzięki prawdziwym testom jednostkowym testujesz w granicach piaskownicy i powinno być jasne. Jeśli programista napisał zapytanie SQL, które nie powiodło się w QA / PROD, oznacza to, że nawet wcześniej go nie przetestował.

vidalsasoon
źródło
+1 za „nie możesz ich kontrolować (mogą przejść w fazie testowania integracji, ale nie powiodły się w produkcji)” .
Tulains Córdova,
Państwo może kontrolować ich satysfakcjonujący stopień.
el.pescado,
Rozumiem twój punkt widzenia, ale myślę, że kiedyś było to bardziej prawdziwe niż dzisiaj? Dzięki automatyzacji i narzędziom (takim jak Docker) można dokładnie i niezawodnie replikować i powtarzać konfigurację wszystkich zależności binarnych / serwerów w testach integracyjnych. Oczywiście tak, fizyczny sprzęt (i usługi innych firm itp.) Może zawieść.
mindplay.dk
5
Absolutnie się nie zgadzam. Powinieneś napisać (dodatkowe) testy integracji, ponieważ zależności zewnętrzne mogą zawieść. Zależności zewnętrzne mogą mieć swoje dziwactwa, których najprawdopodobniej przeoczysz, kpiąc ze wszystkiego.
Paul Kertscher,
1
@PaulK wciąż zastanawiam się, którą odpowiedź oznaczyć jako zaakceptowaną, ale przechylam się do tego samego wniosku.
mindplay.dk