Testowanie bazy danych

Udostępnij na: Facebook

Autor: Piotr Zieliński

Opublikowano: 2010-10-27

W celu wykonania czynności opisanych w artykule należy pobrać przykładową bazę danych AdventureWorks z CodePlex.

Wprowadzenie

Silniki bazodanowe oferują coraz większe możliwości. W bazach danych, oprócz czystych danych, implementowane są nierzadko skomplikowane funkcje i procedury. Bardzo prawdopodobne jest, że zaimplementowane funkcje wykonują zaawansowane obliczenia matematyczne (np. z dziedziny statystyki). Bazy danych stały się już nie tylko pojemnikiem na dane, a osobną warstwą w systemach komputerowych. Wynika z tego, że warto zastanowić się nad jej przetestowaniem. Co dokładnie w bazie danych możemy przetestować?

  • Procedury oraz funkcje – testy jednostkowe sprawdzające, czy kod zwraca poprawne wyniki. Weryfikacja poprawności wygląda zatem bardzo podobnie do testowania zwykłego kodu napisanego w C#. Należy zdefiniować parametry wejściowe oraz oczekiwaną wartość wyjściową. Następnie należy wywołać badaną funkcje i sprawdzić, czy zwrócona wartość  jest taka sama jak oczekiwana.
  • Kolumny wyliczane – warto sprawdzić, czy kolumna prawidłowo zwraca wynik. Test przypomina również test jednostkowy, ponieważ oparty jest na wartości oczekiwanej i rzeczywistej (obliczonej w kolumnie).
  • Struktura bazy danych – weryfikacja liczby oraz typów kolumn. Można również sprawdzić, czy w bazie znajdują się wszystkie wymagane tabele. Pozwala to uniknąć błędów związanych z aktualizacją struktury bazy (np. poprzez dodanie lub usunięcie kolumny w tabeli).
  • Bezpieczeństwo – przetestowanie, czy dani użytkownicy istnieją w bazie oraz czy mają przypisane odpowiednie pozwolenia. Można również sprawdzić, czy dany użytkownik posiada dostęp do konkretnych tabel lub czy dostęp jest zabroniony (co powinno spowodować spodziewany wyjątek).
  • Test zawartości – często tabele zawierają dane związane z szablonami lub tzw. słownikami. Podczas testów należy sprawdzić, czy wymagane dane rzeczywiście znajdują się w tabelach.

Utworzenie projektu

Przed implementacją konkretnych testów należy utworzyć odpowiedni projekt. W tym celu wykonujemy:

1.       Z menu głównego wybieramy File->New->Project.

2.       Zaznaczamy TestProject i klikamy w przycisk OK.

Rysunek 1. Utworzenie projektu testowego.

3.       Po utworzeniu projektu testowego należy dodać test jednostkowy dla bazy danych. W tym celu w menu kontekstowym w Solution Explorer wybieramy Add->New Test. Następnie w otworzonym oknie zaznaczamy Database Unit Test i klikamy przycisk OK.

Rysunek 2. Utworzenie testu jednostkowego dla bazy danych.

4.       Kolejnym etapem jest konfiguracja połączenia do bazy danych – należy wskazać lokalizację oraz adresy bazy.

Rysunek 3. Konfiguracja połączenia.

5.       Projekt dla testów jednostkowych bazy danych został utworzony. Po zatwierdzeniu połączenia powinien pojawić się designer.

Rysunek 4. Designer to główne narzędzie podczas tworzenia testów bazy danych.

 

Test procedury składowanej

Dzięki rozbudowanemu IDE przetestowanie procedur składowanych jest dość łatwe:

1.       Klikamy na ikonie z zielonym krzyżykiem „Add Test”.

2.       W otwartym oknie wpisujemy nazwę testu.

Rysunek 5. Nazwa testu sprawdzającego poprawność procedury składowanej GetManagerEmployees.

3.       Powinno pojawić się okno, w którym należy podać kod T-SQL wywołujący daną procedurę lub funkcję. W naszym przypadku będzie to:

EXEC uspGetManagerEmployees 6

Rysunek 6. Zapytanie T-SQL wywołujące procedurę.

4.       Tak jak w klasycznych testach jednostkowych, domyślnie wygenerowana została asercja Inconclusive. W rozważanym przypadku nie jest ona potrzebna i należy ją usunąć.

5.       Z poziomu IDE można dodawać różne asercje sprawdzające, m.in. sumę kontrolną zwróconych wierszy, czas wykonania zapytania, strukturę czy liczbę zwróconych wierszy. W naszym przykładzie dodajemy jedną asercję sprawdzającą, czy procedura zwróci 8 wierszy.

Rysunek 7. Dodanie asercji jest bardzo intuicyjne – całość odbywa się za pomocą graficznego interfejsu.

6.       Zapisujemy zmiany i zamykamy okno.

7.       Z menu głównego Visual Studio wybieramy Test->Windows->TestView. Jeśli w okienku nie pojawił się utworzony właśnie test, należy kliknąć przycisk Refresh.

8.       Zaznaczamy GetManagerEmployeesTest, a następnie uruchamiany test (menu kontekstowe -> Run Selection).

9.       Po wykonaniu testu pojawi się standardowy raport prezentujący wyniki.

Rysunek 8. Test dla podanej asercji został zaliczony.

Automatyczne generowanie testów jednostkowych

W poprzednich krokach został utworzony test jednostkowy dla procedury składowanej. Zaprezentowany sposób jest w pełni poprawny, jednak czasami niewygodny z powodu konieczności pisania sporej ilości kodu. Lepszym sposobem jest wygenerowanie szablonu dla funkcji lub procedury,  a następnie uzupełnienie kodu konkretnymi danymi wejściowymi. Najpierw jednak należy stworzyć dodatkowy projekt:

1.       Z menu głównego wybierany File->New->New Project.

2.       Wybieramy SQL Server 2008 Database Project.

Rysunek 9. Przed automatycznym wygenerowaniem szablonów dla testów jednostkowych należy utworzyć projekt bazodanowy.

3.       Klikamy na nowo utworzonym projekcie, a następnie z menu kontekstowego wybieramy Import Database Objects and Settings.

4.       W otwartym oknie zaznaczamy bazę danych (Adventure Works) i rozpoczynamy import poprzez kliknięcie w przycisk Start.

Rysunek 10. Ustawianie bazy danych.

5.       Po zakończeniu importu pojawi się okno raportujące dokonane zmiany.

Rysunek 11. Struktura bazy danych została pobrana.

Po pobraniu struktury można wygenerować pierwszy szablon testu jednostkowego (dla funkcji uspGetBillOfMaterials). W tym celu:

1.       Przechodzimy do węzła Schema Objects->Schemas->dbo->Programmability->Stored Procedures-> uspGetBillOfMaterials.

Rysunek 12. Skrypty SQL wszystkich obiektów w bazie danych.

2.       Klikamy na procedurze i z menu kontekstowego wybieramy View Object in Schema View-> uspGetBillOfMaterials. Pojawi się okno pokazujące strukturę procedury.

Rysunek 13. Struktura procedury.

3.       Klikamy w nazwę procedury (okno Schema View) i wybieramy Create Unit Tests.

4.       Projekt dla testów został już utworzony wcześniej, więc w nowo otwartym oknie wybieramy istniejący już projekt.

Rysunek 14. Należy wskazać projekt docelowy dla testów jednostkowych.

5.       Po zatwierdzeniu zostanie automatycznie wygenerowany szablon testu jednostkowego:

Rysunek 15. Wygenerowany szablon testu jednostkowego.

6.       Uzupełniamy szablon prawidłowymi danymi wejściowymi oraz dodajemy  asercje.

Rysunek 16. Szablon wystarczy uzupełnić wartościami parametrów wejściowych oraz asercjami.

7.       Po skonfigurowaniu testu można uruchomić wszystkie utworzone testy jednostkowe i upewnić się, że działają prawidłowo:

Rysunek 17. Na tym etapie wszystkie testy powinny zostać wykonane pozytywnie.

Typy  asercji

W testach jednostkowych bardzo istotną część kodu stanowi asercja. Testując procedury oraz funkcje, można użyć prostej asercji z wykorzystaniem RAISEERROR:

EXEC [dbo].[procedure]

IF (@@ROWCOUNT <> 10)

  RAISERROR('jakis tekst’,11,1)

Lepszym rozwiązaniem jednak jest wykorzystanie asercji zdefiniowanych przez Visual Studio, o których była już mowa we wcześniejszych częściach artykułu. Warto jednak przyjrzeć się im dokładniej:

Tabela 1. Typy asercji dla testów bazodanowych.

Asercja Opis
Data Checksum Sprawdza sumę kontrolną zwróconego zbioru danych.
Expected Schema Sprawdza strukturę (kolumny, typy itp.).
Row Count Sprawdza liczbę zwróconych wierszy.
Scalar Value Sprawdza, czy zwrócony wynik zawiera określoną wartość (skalar).
Empty Resultset Sprawdza, czy zwrócony zbiór danych jest pusty.
Not Empty Resultset Sprawdza, czy zwrócony zbiór danych nie jest pusty.
Execution Time Sprawdza, czy wykonanie testu mieści się w określonym czasie.
Inconclusive Wynik nierozstrzygnięty.

Inicjalizacja oraz zakończenie testów

Visual Studio pozwala również na uruchomienie skryptów przed i po każdym teście. Wystarczy wybrać odpowiednią procedurę\funkcje i kliknąć w designerze na Pre-Test lub Post-Test.

Rysunek 18. Skrypty mogą być wykonane zarówno przed, jak i po teście.

W testach pre-test oraz post-test można przede wszystkim umieścić dowolny skrypt T-SQL. Ponadto, tak jak w przypadku zwykłych testów, do dyspozycji mamy kilka asercji. Większość z nich została już przedstawiona w tabeli 1. Warto jednak zwrócić uwagę na asercję Expected Schema, która umożliwia sprawdzenie, czy tabele posiadają stosowną strukturę (kolumny, typy danych).

Ponadto można zdefiniować skrypty odpalane jednokrotnie przed i po wykonaniu wszystkich testów. Jest to doskonałe miejsce na skrypty instalacyjne, niezbędne do przeprowadzenia testów. Wystarczy w designerze zamiast konkretnej funkcji wybrać Common Scripts, a następnie w zależności od potrzeb Test Initialize lub Test Cleanup.

Rysunek 19. Skrypty można również uruchamiać przed  i po wykonaniu wszystkich testów.


          

Piotr Zieliński

Absolwent informatyki o specjalizacji inżynieria oprogramowania Uniwersytetu Zielonogórskiego. Posiada szereg certyfikatów z technologii Microsoft (MCP, MCTS, MCPD). W 2011 roku wyróżniony nagrodą MVP w kategorii Visual C#. Aktualnie pracuje w General Electric pisząc oprogramowanie wykorzystywane w monitorowaniu transformatorów . Platformę .NET zna od wersji 1.1 – wcześniej wykorzystywał głównie MFC oraz C++ Builder. Interesuje się wieloma technologiami m.in. ASP.NET MVC, WPF, PRISM, WCF, WCF Data Services, WWF, Azure, Silverlight, WCF RIA Services, XNA, Entity Framework, nHibernate. Oprócz czystych technologii zajmuje się również wzorcami projektowymi, bezpieczeństwem aplikacji webowych i testowaniem oprogramowania od strony programisty. W wolnych chwilach prowadzi blog o .NET i tzw. patterns & practices.