Zaczynam nowy projekt i bardzo bardzo staram się używać TDD do kierowania projektem. Naciskam od lat i wreszcie uzyskałem zgodę na poświęcenie dodatkowego czasu na ten projekt, aby go wykorzystać, podczas gdy uczę się, jak robić to poprawnie.
To jest nowy moduł do połączenia z istniejącym systemem. Obecnie dostęp do wszystkich danych odbywa się za pośrednictwem usług internetowych, które w większości stanowią jedynie cienkie opakowanie procedur przechowywanych w bazie danych.
Jednym z wymagań jest to, że dla danego sklepu zwracam wszystkie zamówienia, które są uważane za ważne dla tej aplikacji. Zamówienie zakupu uważa się za ważne, jeśli jego data wysyłki przypada w danym zakresie od daty otwarcia sklepów (dotyczy to nowych sklepów).
Teraz nie mogę umieścić tej logiki w kodzie aplikacji, ponieważ nie zamierzam przywracać miliona PO, aby uzyskać tuzin, które mogą ubiegać się o ten sklep, biorąc pod uwagę powyższe ograniczenie.
Myślałem, że mogę przekazać zakres dat do procedury GetValidPOs i użyć tych wartości do zwrócenia prawidłowych zamówień zakupu. Ale co, jeśli dodamy kolejny wymóg do tego, co jest uważane za prawidłową PO?
Jak to przetestować i sprawdzić, czy działa dalej? Nie używamy ORM i jest mało prawdopodobne. I nie mogę zadzwonić do DB w moim teście.
Utknąłem.
Inną moją myślą jest to, że niektóre udają, że zwracają prawidłowe dane, inne, które zwracają niektóre złe dane, i lokalne repozytorium zgłasza wyjątek, jeśli wystąpią złe dane, i przetestuj, czy wyjątek zostanie zgłoszony, jeśli nieprawidłowe dane zostaną zwrócone przez proc GetValidPOs (lub próbka użyta do testowania).
Czy to ma sens? Czy jest jakiś lepszy sposób?
AKTUALIZACJA: Wydaje mi się, że mogę używać EF. Teraz muszę tylko wymyślić, jak go używać i sprawić, by był testowalny, a jednocześnie nadal polegać na procedurach przechowywanych i trudnościach z rozproszeniem danych w kilku bazach danych.
źródło
Odpowiedzi:
Jest to główny minus procedur przechowywanych w erze TDD. Mają pewne pozytywne strony, nawet teraz, ale z definicji każdy test, który wykonuje zapisany proc, nie jest testem jednostkowym; w najlepszym razie jest to test integracyjny.
Zwykłym rozwiązaniem, zakładającym, że architektura nie może zmienić się na użycie ORM, nie jest umieszczanie tych testów w zestawie testów jednostkowych; zamiast tego umieść testy w pakiecie integracyjnym. Nadal możesz uruchomić test, ilekroć chcesz sprawdzić, czy działa, ale ponieważ koszt związany z przygotowaniem testu (zainicjowanie bazy danych z odpowiednimi danymi testowymi) jest wysoki i dotyka zasobów agenta testów jednostkowych twojego build-bota mieć dostęp do, nie powinno być w pakiecie testów jednostkowych.
Nadal możesz testować jednostkowo kod, który wymaga danych, poprzez wyodrębnienie wszystkiego, czego nie możesz przetestować jednostkowo (klasy ADO.NET), do klasy DAO, którą możesz następnie wyśmiewać. Następnie można zweryfikować, czy oczekiwane wywołania są wykonywane przez użycie kodu i odtworzenie rzeczywistych zachowań (takich jak nie znajdowanie wyników), umożliwiając testowanie różnych przypadków użycia. Jednak faktyczne skonfigurowanie SqlCommand do wywoływania przechowywanego proc jest właściwie ostatnią rzeczą, którą można przetestować jednostkowo, oddzielając tworzenie poleceń od wykonywania poleceń i wyśmiewając executora poleceń. Jeśli brzmi to jak oddzielenie obaw, może być; pamiętajcie: „nie ma problemu, którego nie da się rozwiązać za pomocą innej warstwy pośredniej, z wyjątkiem posiadania zbyt wielu warstw pośrednich”. W pewnym momencie musisz powiedzieć „dość; po prostu nie mogę tego przetestować jednostkowo, my”
Inne opcje:
Przetestuj przechowywany proc przy użyciu „krótkotrwałej” instancji DBMS, takiej jak SQLite. Zwykle łatwiej jest to zrobić, gdy używasz ORM, ale test można następnie wykonać „w pamięci” (lub przy użyciu wstępnie ustawionego pliku bazy danych dołączonego do pakietu testowego). Nadal nie jest to test jednostkowy, ale można go uruchomić z wysokim stopniem izolacji (DBMS jest częścią działającego procesu, a nie czymś, z czym się łączysz zdalnie, co może znajdować się w środku pakietu testowego innego użytkownika). Minusem jest to, że zmiany w przechowywanym proc mogą wystąpić w produkcji bez testu odzwierciedlającego zmianę, więc musisz być zdyscyplinowany, aby upewnić się, że najpierw wprowadzono zmianę w środowisku testowym.
Rozważ uaktualnienie do ORM. ORM z dostawcą Linq (praktycznie wszystkie te, które są w powszechnym użyciu, mają taki), umożliwiłby zdefiniowanie zapytania jako instrukcji Linq; taka instrukcja może być następnie przekazana fałszywemu repozytorium, które ma w pamięci kolekcję danych testowych do zastosowania. W ten sposób możesz sprawdzić, czy zapytanie jest poprawne, nawet nie dotykając DB (powinieneś nadal uruchomić zapytanie w środowisku integracyjnym, aby sprawdzić, czy dostawca Linq może poprawnie przetrawić zapytanie).
źródło
Radzę podzielić i podbić . Na razie zapomnij o bazie danych i trwałości i skoncentruj się na testowaniu fałszywych implementacji repozytoriów lub obiektów dostępu do danych.
Wyśmiewałbym repozytorium, które zwraca zamówienia. Utwórz makietę z dwudziestoma dziwnymi zamówieniami zakupu.
Stub połączenie do GetValidPOs, aby wywoływał twoją próbkę, a nie procedurę bazy danych.
Potrzebujesz testu jednostkowego, aby upewnić się, że poprawne dane są zwracane z próbnego.
Potrzebujesz również testu integracji, aby upewnić się, że poprawne dane są zwracane z bazy danych. Test integracji wymagałby pewnej konfiguracji i czyszczenia. Na przykład przed uruchomieniem testu integracji należy zaszczepić bazę danych, uruchamiając skrypt. Sprawdź, czy skrypt działał. Zapytaj bazę danych, wywołując procedury składowane. Sprawdź, czy wyniki są poprawne. Oczyść bazę danych.
Jak już powiedziałem, potrzebujesz makiety, która zwraca przynajmniej niektóre dane, które możesz zapytać.
Podczas wyszukiwania danych chcesz mieć pewność, że Twój system z łatwością obsłuży wyjątki. Dlatego kpisz sobie z zachowania, aby generowało wyjątki w niektórych scenariuszach. Następnie piszesz testy, aby upewnić się, że Twój system może z powodzeniem obsługiwać te wyjątki.
źródło
Tak jak testowanie jednostkowe Java lub JavaScript oznacza pisanie testów jednostkowych przy użyciu języka Java dla java, a testowanie jednostkowe funkcji Javascript za pomocą Javascript, pisanie automatycznych testów, które doprowadzą Cię do napisania procedur przechowywanych, oznacza, że biblioteka testów jednostkowych, której szukasz, jest oparta na przechowywanej procedury.
Innym sposobem jest użycie procedur przechowywanych do przetestowania procedur przechowywanych, ponieważ:
Podobnie jak TDD w języku OO, chcesz, aby test jednostkowy skonfigurował tylko wiersz danych, aby przetestować to, czego potrzebuje do procedury (minimalizm, tylko to, czego potrzebują twoje proste testy). W rezultacie będziesz mieć kilka prostych testów jednostkowych dla każdej procedury składowanej. Te proste testy będą łatwiejsze w utrzymaniu niż skomplikowane testy, które zależą od dużego zestawu danych, który nie łatwo odwzorowuje z powrotem na to, czego faktycznie potrzebuje test.
źródło