Testowanie baz danych MS SQL za pomocą Visual Studio 2015. Część II.

O testowaniu baz danych mówi i pisze się niewiele. Okazuje się jednak, że istnieje sporo możliwości szybkiego generowania automatycznych testów do baz danych. Zapraszamy do lektury drugiej części artykułu.

 

4. Tworzenie automatycznych testów baz danych MS SQL w Visual Studio 2015

W poprzednim rozdziale została przedstawiona konfiguracja środowiska testowego. Ten rozdział będzie przedstawiał definiowanie samych testów. Zarządzanie testami ułatwia sekcja [Test Explorer], którą należy włączyć z miejsca pokazanego poniżej:

 

Jeżeli po włączeniu listy testów nie będzie widoczny żaden test, to należy zapisać wszystkie zmiany i przebudować solucję. Następnie ukaże się lista testów (Test Explorer):

 

Metodę znajdującą się w klasie UnitTest1.cs należy usunąć, ponieważ będzie wykonywana przy włączaniu testów. W celu edycji już istniejącego testu należy włączyć widok klasy zawierającej testy jako Designer. 

 

Pojawi się formularz, do którego test automatyczny można dodać ręcznie bez konieczności programowania:

 

Domyślnie każdy dodany test ma zaznaczony typ Inconclusive. Opcja ta oznacza, że test będzie pominięty podczas uruchomienia listy testów, która go zawiera. Taki test należy usunąć czerwonym krzyżykiem z listy widocznej wyżej na obrazku, a następnie dodać nowe testy.

 

Przykład:

Funkcja dbo_ufnGetAccountingEndDate w bazie danych AdventureWorks, dla której został wygenerowany test w poprzednim rozdziale, zwraca datę, a później zapisuje ją w postaci wartości tekstowej. Można dla niej utworzyć również dodatkowy test, który będzie sprawdzał, czy wykonanie funkcji zmieści się w odpowiednim czasie.

Aby dodać nowe testy należy otworzyć plik z rozszerzeniem *.resx (umieszczony w podglądzie solucji), klikając w niego dwa razy. Wówczas ukaże się następujący formularz:

 

Następnie należy kliknąć dwa razy w pole zaznaczone na obrazku i skopiować tekst z pola [Value]:

 

Po skopiowaniu tekstu osoba projektująca test otwiera klasę SqlServerFunctionsTests.cs wybierając opcję [View Designer]. Kolejne kroki to:

  • usunięcie istniejącego testu:

 

  • wybranie typu dodawanych testów:

 

  • dodanie nowych testów za pomocą znaku z zielonym plusem i wklejenie skopiowanego wcześniej tekstu:

 

Pierwszy test należy jeszcze skonfigurować, klikając przycisk zaznaczony niżej na obrazku:

 

  • osoba definiująca test klika [Select Connection]
  • wskazuje bazę danych,
  • klika [Retrieve].

 

Po wykonaniu wyżej opisanych kroków (jeśli zapytanie do bazy jest prawidłowe) pokaże się wynik jak poniżej:

 

Analogicznie po prawej stronie (pod oknem z solucją) zmieniają się parametry drugiego testu. Po zapisaniu zmian dane testowe wejściowe oraz wyjściowe, testy w postaci kodu w klasie SqlServerFunctionsTests.cs:

// 
// dbo_ufnGetAccountingEndDateTest_TestAction
//
dbo_ufnGetAccountingEndDateTest_TestAction.Conditions.Add(checksumCondition1);
dbo_ufnGetAccountingEndDateTest_TestAction.Conditions.Add(executionTimeCondition1);
resources.ApplyResources(dbo_ufnGetAccountingEndDateTest_TestAction, "dbo_ufnGetAccountingEndDateTest_TestAction");
 // 
 // dbo_ufnGetAccountingEndDateTest1_TestAction
 // 
dbo_ufnGetAccountingEndDateTest1_TestAction.Conditions.Add(inconclusiveCondition2);
resources.ApplyResources(dbo_ufnGetAccountingEndDateTest1_TestAction, "dbo_ufnGetAccountingEndDateTest1_TestAction");
// 
// inconclusiveCondition2
// 
inconclusiveCondition2.Enabled = true;
inconclusiveCondition2.Name = "inconclusiveCondition2";
// 
// dbo_ufnGetAccountingEndDateTestData
// 
this.dbo_ufnGetAccountingEndDateTestData.PosttestAction = null;
this.dbo_ufnGetAccountingEndDateTestData.PretestAction = null;
this.dbo_ufnGetAccountingEndDateTestData.TestAction = dbo_ufnGetAccountingEndDateTest_TestAction;
// 
// dbo_ufnGetAccountingEndDateTest1Data
//
this.dbo_ufnGetAccountingEndDateTest1Data.PosttestAction = null;
this.dbo_ufnGetAccountingEndDateTest1Data.PretestAction = null;
this.dbo_ufnGetAccountingEndDateTest1Data.TestAction = dbo_ufnGetAccountingEndDateTest1_TestAction;
// 
// checksumCondition1
// 
checksumCondition1.Checksum = "1125392345";
checksumCondition1.Enabled = true;
checksumCondition1.Name = "checksumCondition1";
// 
// executionTimeCondition1
// 
executionTimeCondition1.Enabled = true;
executionTimeCondition1.ExecutionTime = System.TimeSpan.Parse("00:00:30");
executionTimeCondition1.Name = "executionTimeCondition1";

 

Wyżej opisany przykład prezentuje dodawanie testów dla jednej funkcji skalarnej w bazie danych. Nazwa testu  dbo_ufnGetAccountingEndDateTest_TestAction jest tworzona automatycznie w taki sposób, że pierwsza część nazwy testu  jest brana z nazwy funkcji czy procedury z bazy, a druga część to człon TestAction. Jeśli istnieje potrzeba wygenerowania kilku testów do jednej funkcji, to będą one indeksowane automatycznie poprzez dodanie liczby po pierwszym członie nazwy, np. dbo_ufnGetAccountingEndDateTest1_TestAction.

Wartości danych testowych:

  • checksumCondition1.Checksum = "1125392345",
  • executionTimeCondition1.ExecutionTime = System.TimeSpan.Parse("00:00:30").

są również automatycznie tworzone w momencie definiowania testów. Kod może być modyfikowany przez testera, co jednak wymaga umiejętności programowania. 

Typ Data Checksum, jak wynika z przykładu, zamienia wynik funkcji skalarnej na string i porównuje wynik z zapamiętanym oczekiwanym rezultatem. Są dostępne jeszcze inne typy testów np. Skalar Value, Row Count, Empty ResultSet, w których osoba projektująca wpisuje oczekiwaną liczbę lub inną wartość ręcznie, bez potrzeby łączenia się z bazą w celu uzyskania rezultatu. Analogicznie dodaje się testy dla procedur, funkcji tabelarycznych, czy widoku. Należy tylko wybrać odpowiedni typ testu. 

 

5. Dodawanie testów do istniejącej klasy

Dodawanie testów do istniejącego zestawu może odbyć się na dwa sposoby:

  • można stworzyć nową klasę dla testu,
  • można dodać testy do istniejącej klasy.

 

W celu utworzenia nowej klasy należy wybrać w widoku solucji dowolną funkcję, a następnie wybrać opcję [Create Unit Test]:

 

Kolejny krok to wybranie funkcji, które należy przetestować:

 

oraz podjęcie decyzji czy tworzyć nową klasę czy wykorzystać istniejącą. Następnie należy wybrać projekt (najlepiej nie zmieniać domyślnych ustawień żeby testy były czytelne). W przykładzie dodane zostaną testy do istniejącej klasy. Jeżeli osoba definiująca testy kliknie [OK], to w pliku z rozszerzeniem *.resx pojawi się lista dodanych nazw testów z zapytaniami:

 

Sugestia dla czytelnika jest taka, żeby testy były pogrupowane wg następujących typów odpowiednio w osobnych klasach:

  • funkcji skalarnych,
  • funkcji zwracających tabele, 
  • procedur, 
  • widoków,
  • triggerów,

ponieważ takie podejście ułatwi zrozumienie oraz czytanie testów. Nic nie stoi na przeszkodzie, aby samemu dopisać fragment kodu, który wzbogaci wygenerowane testy, czyniąc je lepszymi pod różnym kątem. Istnieje dodatkowy sposób pogrupowania testów – dodanie swojej listy, klikając [Add to Playlist], jak pokazano niżej:

 

Nowe testy nie muszą być od razu widoczne w sekcji [Test Explorer]. W takim przypadku należy zbudować solucję jeszcze raz. Przykładowo, jeśli dodane zostaną testy dla procedur, to pojawią się one już na pewno w sekcji [Test Explorer] po zbudowaniu solucji:

 

Testy, które należy edytować wybiera się w polu zaznaczonym niżej na obrazku:

 

Obok zaznaczonego wyżej pola wyboru po prawej stronie znajduje się pole, które domyślnie zawiera wartość Test. To oznacza, że użytkownik definiuje dane dla testu. Wspomniane pole zawiera wartości Pre-test oraz Post-test. Te wartości służą do ustawiania czynności, które mają być wykonane przed i po teście. Zawsze do każdego obiektu zdefiniowanego w bazie danych (który się wykonuje) można dodać test z warunkiem czasowym. Natomiast inne typy testów muszą zostać przemyślane przez osobę projektującą. Uruchomienie testów odbywa się przez wybór listy lub zaznaczenie kilku testów jednocześnie i wybraniu polecenia [Run] pod prawym przyciskiem myszki. Więcej informacji na temat testów bazy danych MS SQL można znaleźć na stronach:

 

6. Podsumowanie

Celem napisania artykułu było przedstawienie sposobu generowania automatycznych testów do baz danych MS SQL. Okazuje się że istnieje sporo możliwości generowania takich testów, a dodatkową ich zaletą jest to, że nie jest wymagana umiejętność programowania oraz generuje się je bardzo szybko. Zdarza się, że testerzy ręczne weryfikują obiekty zwracające wartości lub tabele w bazach danych. Istnieje możliwość dopisania kodu, wykonania fragmentu skryptu przed testem oraz po teście. Testy zaprojektowane w Visual Studio 2015 można dodać jak projekt do solucji aplikacji, ustawić ciągłą integrację wersji oraz uruchamiać je po każdym buildzie aplikacji (proces budujący aplikację wraz z nowymi zmianami). Po uruchomieniu testów, do katalogu wskazanego przez osobę tworzącą testy, będzie wrzucany log z testów. Visual Studio umożliwia również ręczne wygenerowanie raportu z testów. 

Testy automatyczne bazy danych z pewnością nie zastąpią wszystkich testów, które można zrobić manualnie, ale zastąpią część z nich, a przynajmniej najprostsze. Na pewno jednak pozwolą zaoszczędzić czas ich wykonywania. 

 

Autor: Marek Żukowicz

 

 

SPRAWDŹ TAKŻE
Testowanie baz danych MS SQL za pomocą Visual Studio 2015. Część I. 

 

 

Pobierz artykuł [plik PDF] >>

 

 
 

Najbliższe terminy szkoleń

Partnerzy

Narzędzia testerskie