Testowanie jednostkowe - aplikacja powiązana z bazą danych

15

Jakie byłoby najlepsze podejście do testowania jednostkowego modelu zintegrowanego z aplikacją ściśle powiązaną z bazą danych?

Konkretnym scenariuszem jest tutaj koszyk na zakupy - chciałbym móc przetestować dodawanie usuwania i pobierania przedmiotów z koszyka, a także logikę ustalania cen itp. To wszystko moim zdaniem wymaga dostępu do bazy danych, chociaż kilkakrotnie przeczytałem, że należy unikać dostępu do bazy danych.

użytkownik1189880
źródło
1
Ciekawe, że głosowane są odpowiedzi, które faktycznie mówią „przepisz kod aplikacji”
AD7six,

Odpowiedzi:

10

Wstrzykiwanie zależności jest jednym ze sposobów radzenia sobie z tym. Możesz skonfigurować testową bazę danych, aby naśladować koszyk, lub nawet napisać kod, który „potwierdzi” transakcję klienta. Następnie w czasie wykonywania oprogramowanie wybierze, z którym komponentem się połączyć.

Po prostu nie łącz się z produkcyjną bazą danych podczas testowania!

chrisaycock
źródło
1
Dzięki DI i właściwemu projektowi aplikacji powinieneś być w stanie testować bez żadnej bazy danych --- pod warunkiem, że wstrzyknięty przez Ciebie makieta zapewnia wystarczająco szczegółowe wyśmiewanie bazy danych zaplecza.
Peter K.
4

W teście jednostkowym musisz zdefiniować granicę tego, co testujesz. Testowanie jednostkowe różni się od testowania integracyjnego. Jeśli logika wyceny jest niezależna od zawartości koszyka, należy to przetestować osobno. Jeśli tak nie jest, a wszystkie moduły są ściśle ze sobą powiązane, zbuduj środowisko testowe, które naśladuje produkcję w jak największym stopniu i pracuj z tym. Nie wierzę, że skróty i symulacja pomagają na dłuższą metę.

Bez szans
źródło
2

Model nie powinien zależeć od (konkretnego) DB. Jeśli zna tylko abstrakcyjną bazę danych (czytaj „interfejs”), która jest przekazywana do modelu, możesz zastąpić bazę danych próbnym obiektem .

W programowaniu obiektowym , atrapa obiektu symulowane są obiekty, które naśladują zachowanie rzeczywistych obiektów w kontrolowanych sposobów. Programista zwykle tworzy próbny obiekt w celu przetestowania zachowania jakiegoś innego obiektu, podobnie jak projektant samochodu używa manekina do testów zderzeniowych do symulacji dynamicznego zachowania człowieka w zderzeniu z pojazdem ...

EricSchaefer
źródło
1

Miałem podobny problem - nie miałem możliwości zagwarantowania, że ​​mój testowy DB zachowuje wartości. W przyszłości otrzymam np. Inne ceny.

Wyodrębniłem potrzebne dane do małego sqlite -DB i użyłem tego DB do moich testów. Test-DB jest teraz częścią konfiguracji mojego testu jednostkowego.

knut
źródło
2
Celem testów jednostkowych jest przetestowanie kodu w izolacji. Jeśli używasz bazy danych sqllite, to nie jest ona odizolowana. Również niespójności między bazami danych mogą powodować błędy
Tom Squires
0

„Najlepsze” jest subiektywne, ale możesz po prostu użyć testowego połączenia db.

Użyj urządzeń, aby załadować niektóre dane testowe (przykładowe produkty do kupienia), a następnie napisz przypadek testowy dla klasy / funkcji, którą chcesz przetestować.

AD7six
źródło
Opisywanie testów jednostkowych testujących funkcję, która działa na bazę danych jako testy integracyjne, jest dość mylące @murph.
AD7six,
1
Ok, teraz jestem głęboko zdezorientowany - jeśli chodzi o bazę danych, według większości definicji nie jest to test jednostkowy, ponieważ nie jest samodzielny. Jeśli masz bazę danych, to uruchamiasz testy na wyższym poziomie, który miał zależności, które polegają na „łączeniu” rzeczy. Niezależnie od tego nie jest to dla mnie jasne wyjaśnienie, jak rozwiązać problem.
Murph
0

Zbudowałem wtyczkę do Symfony 1.4 (PHP), aby rozwiązać ten problem (między innymi). Jest modelowany na podstawie sposobu działania środowiska testowego Django (Python) : środowisko to buduje i wypełnia osobną testową bazę danych przed rozpoczęciem każdego testu, i niszczy testową bazę danych po zakończeniu każdego testu.

Miałem kilka obaw związanych z tą strategią, zarówno pod względem wydajności (jeśli schemat się nie zmienia, dlaczego po prostu nie wyczyścić danych zamiast odbudowywania całej struktury?) I wygody (czasami chcę sprawdzić bazę danych po test niepowodzenia, więc nie niszcz go bezkrytycznie!), więc podjąłem nieco inne podejście.

Przed uruchomieniem pierwszego testu baza danych jest niszczona i odbudowywana, na wypadek zmiany modelu od ostatniego testu. Przed każdym kolejnym testem dane w bazie danych są usuwane, ale struktura nie jest odbudowywana (chociaż w razie potrzeby można uruchomić ręczną odbudowę z testu).

Selektywnie ładując urządzenia danych w każdym teście, można stworzyć odpowiednie środowisko dla tego testu bez ingerencji w kolejne testy. Pliki urządzeń mogą być również ponownie użyte, co czyni to zadanie o wiele mniej uciążliwym (chociaż nadal jest to moja najmniej ulubiona część pisania testów!).

W obu ramach testowych adapter bazy danych jest skonfigurowany do używania połączenia testowego zamiast połączenia „produkcyjnego”, aby zapobiec uszkodzeniu istniejących danych przez wykonanie testu.


źródło
0

Powiedziałbym, po prostu idź dalej i użyj urządzeń, aby wstępnie załadować dane. Tak właśnie wydają się działać ogólne ramy testowania jednostkowego podczas testowania manipulacji danymi.

Ale jeśli naprawdę chcesz uniknąć konieczności łączenia się z dowolną bazą danych i stosujesz zbyt surową definicję, że testy jednostkowe nie dotykają niczego poza kodem, spójrz na kpiące obiekty - może to dać ci pomysły.

Na przykład zamiast upuszczać SQL bezpośrednio w kodzie, w którym jest on potrzebny, można wywołać metodę, która robi tylko to, co robi SQL. Użyj Person.getPhoneNumber()na przykład zamiast SELECT phone_number FROM person WHERE id = <foo>. Jest nie tylko czystszy i łatwiejszy do zrozumienia na pierwszy rzut oka, ale podczas testowania możesz wyśmiewać obiekt Person, getPhoneNumber()aby zawsze wracał 555-555-5555lub coś, zamiast dotykać bazy danych.

Izkata
źródło
0

Jest to dość łatwe do zrobienia z junitem, jeśli jest trochę za długi.

„Konfiguracja” powinna zdefiniować i wypełnić zestaw tabel tymczasowych.

Następnie można wykonać testy jednostkowe dla wszystkich funkcji aktualizacji, wstawiania i usuwania.

Dla każdego testu wywołujesz metodę aktualizacji, a następnie uruchamiasz trochę SQL, aby zweryfikować oczekiwany wynik.

W fazie „porzucenia” upuszczasz wszystkie stoły.

W ten sposób zawsze uruchamiasz te same testy na tych samych danych początkowych. Jeśli zachowasz tabele między testami, zostaną one „zanieczyszczone” przez nieudane testy, również spójny test „wstaw” jest prawie niemożliwy, ponieważ musisz wymyślać nowe klucze w każdym teście.

James Anderson
źródło