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.
unit-testing
użytkownik1189880
źródło
źródło
Odpowiedzi:
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!
źródło
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ę.
źródło
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 .
źródło
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.
źródło
„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ć.
źródło
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
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 zamiastSELECT 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-5555
lub coś, zamiast dotykać bazy danych.źródło
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.
źródło