Jak (unit-)testować dane intensive PL / SQL application

Nasz zespół chętnie przetestuje nowy kod napisany w ramach działającego projektu rozszerzającego istniejący ogromny system Oracle.

System napisany jest wyłącznie w języku PL/SQL, składa się z tysięcy tabel, setek pakietów procedur składowanych, najczęściej pobierających dane z tabel i/lub wstawiających / aktualizujących inne dane.

Nasze rozszerzenie nie jest wyjątkiem. Większość funkcji zwraca dane z dość złożonej deklaracji SELECT nad wieloma wzajemnie powiązanymi tabelami (z nieco dodaną logiką przed zwracając je) lub dokonać transformacji z jednej skomplikowanej struktury danych do drugiej (skomplikowanej w inny sposób).

Jakie jest najlepsze podejście do jednostkowego testowania takiego kodu?

Nie ma testów jednostkowych dla istniejącej bazy kodu. Co gorsza, tylko pakiety, wyzwalacze i widoki są kontrolowane przez źródła, struktury tabel (w tym rzeczy "alter table" i niezbędne transformacje danych są wdrażane poprzez kanał inny niż kontrola wersji). Nie da się tego zmienić w naszym zakres projektu.

Utrzymanie zestawu danych testowych wydaje się niemożliwe, ponieważ nowy kod jest wdrażany do środowiska produkcyjnego co tydzień, zwykle bez wcześniejszego powiadomienia, często zmieniając strukturę danych (Dodaj kolumnę tutaj, Usuń tam).

Będę zadowolony z każdej sugestii lub odniesienia, które pomogą nam. Niektórzy członkowie zespołu są zmęczeni zastanawianiem się, jak zacząć od naszego doświadczenia z unit-testing nie obejmuje starszych systemów o dużej intensywności danych PL / SQL (tylko te "z książki" greenfield Java projects).

Author: Karel Smutný, 2010-04-19

4 answers

Istnieje kilka różnych narzędzi testowych dla PL/SQL. Steven Feuerstein napisał dwa z nich, utplsqloraz Quest Code Tester dla Oracle (dawniej QUTE). Jestem wielkim fanem utplsql, ale nie ma już aktywnej społeczności wsparcia (a szkoda). To również wydaje się być dość gadatliwy, zwłaszcza jeśli chodzi o konfigurowanie urządzeń testowych. Ma kardynalną wirtualność bycia czystymi pakietami PL / SQL ; kod źródłowy jest nieco strasznie, ale to FOSS.

QCTO jest wyposażony w GUI, co oznacza, że - podobnie jak inne produkty Quest, np. TOAD - jest tylko Windows. Nie automatyzuje generowania danych testowych, ale zapewnia interfejs do ich obsługi. Podobnie jak inne produkty Quest, QCTO jest licencjonowane, chociaż istnieje Darmowa Kopia.

Steven (disclosure, he he jest jednym z moich bohaterów Oracle) napisał Porównanie funkcji wszystkich narzędzi do testowania PL/SQL. Oczywiście QOTC wychodzi topowo, ale myślę, że porównanie jest uczciwe. Zobacz też

Porady dotyczące urządzeń testowych w utplsql

Zarządzanie danymi testowymi do testów jednostkowych może być prawdziwym bólem szyi. Niestety utplsql nie oferuje zbyt wiele, aby wziąć na siebie ciężar. Więc

  • zawsze testuj z znanymi wartościami :
    • Unikaj używania dbms_random;
    • spróbuj ograniczyć użycie sekwencji do kolumn, których wartości nie mają znaczenia;
    • Daty też są trudne. Unikaj daty kodowania twardego: użyj zmiennych wypełnionych sysdate. Naucz się doceniać add_months(), last_day(), interval, trunc(sysdate, 'MM'), itd.
  • odizoluj dane testowe od innych użytkowników. Zbuduj go od podstaw. W miarę możliwości używaj wartości wyróżniających.
  • twórz tylko tyle danych testowych, ile potrzebujesz. Badanie wolumetryczne to inna odpowiedzialność.
  • podczas testowania procedur, które zmieniają dane, tworzy się określone rekordy dla każdego testu jednostkowego.
  • również: nie polegaj na pomyślne wyjście z jednego testu, aby zapewnić wejście z innego testu.
  • W przypadku procedur testowania, które w stosownych przypadkach po prostu składają sprawozdanie z zapisów wymiany danych między testami jednostkowymi.
  • udostępniaj dane ramowe (np. odsyłacze do kluczy głównych) w miarę możliwości.
  • użyj wolnych pól tekstowych (nazwy, opisy, komentarze), aby określić, który test lub testy używają rekordu.
  • zminimalizuj pracę związaną z tworzeniem nowych rekordów:
    • przypisuj tylko wartości, które są konieczne do zestawu testów i ograniczeń tabeli;
    • używaj wartości domyślnych tak często, jak to możliwe;
    • Proceduruj jak najwięcej.
  • Inne rzeczy do zapamiętania:

    • ustawienie urządzenia testowego może być czasochłonnym ćwiczeniem. Jeśli masz dużo danych rozważ zbudowanie procedury konfiguracji danych statycznych, które mogą być uruchamiane raz na sesję i zawierać tylko dane lotne w samym ut_setup. Jest to szczególnie pomocne podczas testowania funkcji tylko do odczytu.
    • pamiętaj, że tworzenie danych testowych jest samo w sobie ćwiczeniem programistycznym, a więc podatnym na błędy.
    • użyj wszystkich funkcji utplsql. utAssert.EqQuery, utAssert.EqQueryValue, utAssert.EqTable, utAssert.EqTabCount i {[9] } są bardzo przydatne funkcje, jeśli chodzi o wnioskowanie wartości lotnych danych.
    • podczas diagnozowania testu, który nie przebiegł tak, jak oczekiwaliśmy, przydatne może być posiadanie danych, które zostały użyte. Rozważ więc procedurę hollow ut_teardown i wyczyszczenie danych testowych na początku ut_setup.

    Obsługa kodu źródłowego

    Komentowanie postu Gary ' ego przypomniało mi jeszcze jedną rzecz, którą możesz uznać za przydatną. Steven f napisał ulplsql jako implementację PL / SQL JUnit, awangardy Javy pierwszego ruchu testowego. Jednak techniki TDD mogą być również stosowane do dużych ilości kodu legacy (w tym kontekście kod legacy to dowolny zestaw programów bez testów jednostkowych).

    Klucz należy pamiętać, że nie trzeba natychmiast poddawać wszystkiego testowi jednostkowemu. Zacznij stopniowo. Zbuduj testy jednostkowe dla nowych rzeczy, najpierw przetestuj . Zbuduj testy jednostkowe dla bitów, które zamierzasz zmienić, zanim zastosujesz zmianę, aby wiedzieć, że nadal działają po wprowadzeniu zmiany.

    Jest wiele myśli w tej dziedzinie, ale (nieuchronnie, jeśli haniebnie) pochodzi głównie od programistów OO. Głównym bohaterem jest Michael Feathers. Przeczytaj jego artykuł Efektywna Praca Z Kodem Starszym . Jeśli okaże się to pomocne, napisał następnie książkę o tej samej nazwie.

     8
    Author: APC,
    Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
    2010-04-20 10:37:30

    Weź następujący scenariusz

    FUNCTION ret_count (local_client_id IN number) RETURN NUMBER IS
      v_ret number;
    BEGIN
      SELECT count(*) INTO v_ret FROM table_1 WHERE client_id = local_client_id;
      RETURN v_ret;
    END;
    

    Bardzo prosta funkcja, ale jest cały bałagan rzeczy, które mogą pójść źle. Konwersje typów danych, indeksowanie, statystyki mogą mieć wpływ na ścieżki zapytań, wydajność i, w niektórych przypadkach, błędy. Istnieje również wiele luźnych powiązań, takich jak ustawienia sesji (np. preferencje językowe). Jeśli ktoś przyszedł i dodał kolumnę "LOCAL_CLIENT_ID" do table_1, zmienia się cała logika funkcji.

    Ja osobiście nie uważam, że TDD nadaje się do to środowisko. Recenzje kodu przez osoby o wiedzy będą miały większą szansę na złapanie problemów.

    Jeśli masz pieniądze, spójrz na RAT Oracle (real application testing) do testowania regresji.

     4
    Author: Gary Myers,
    Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
    2010-04-20 00:11:40

    Użyłem DbFit do testowania kodu PL/SQL. Spróbuj.

     3
    Author: Oliver Michels,
    Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
    2010-04-19 15:30:03

    UtPLSQL może pomóc, ale wygląda na to, że potrzebujesz lepszego sposobu przechowywania danych testowych. Możesz również spojrzeć na Swingbench .

     1
    Author: dpbradley,
    Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
    2010-04-19 15:23:45