SQLite & PDO SQLite support missing in this PHP install - plugin will not work

Tessto - aplikacja wspierająca proces testowania oprogramowania

Sformułowanie zadania projektowego

Testy złożonych systemów i aplikacji wymagają zdefiniowania oraz weryfikacji ogromnej liczby przypadków testowych pokrywających wszystkie wymagania stawiane przez klienta. Aby umożliwić sprawne przeprowadzenie testów konieczne jest umiejętne zarządzanie zespołem testerów, a także dobra komunikacja w jego obrębie. Celem projektu jest stworzenie aplikacji internetowej, stanowiącej odpowiedź na tą potrzebę biznesową. Aplikacja ta ułatwi pracę zespołów zajmujących się testowaniem oprogramowania poprzez umożliwienie im wygodnego zarządzania wymaganiami i przypadkami testowymi oraz usprawnienie samego procesu wykonywania testów. Istotnym elementem aplikacji będzie również funkcjonalność zarządzania zespołem testerów, przydzielania im ról oraz zarządzania poziomem dostępu do poszczególnych projektów. Projekt realizowany będzie przy współpracy z firmą ATSI S.A., zajmującą się tworzeniem oprogramowania. Wymiana doświadczeń z testerami pracującymi na co dzień z tego typu narzędziami pozwoli określić czego brakuje aktualnie dostępnym rozwiązaniom oraz zidentyfikować możliwości wprowadzenia nowych funkcjonalności, które pozytywnie wpłyną na użyteczność oprogramowania. W efekcie powstanie rozwiązanie stanowiące atrakcyjną alternatywę dla już istniejących.

Analiza stanu wyjściowego

Opracowanie projektowanej aplikacji wymaga dokładnej analizy środowiska, w którym przyjdzie jej działać. W ogólnym zarysie na środowisko to składa się wewnętrzna sieć firmy oraz wszystkie systemy i narzędzia wykorzystywane przez testerów, pracujące w tej sieci. Głównym przedmiotem naszego zainteresowania jest aktualnie wykorzystywane w firmie narzędzie wspomagające pracę testerów w zakresie definiowania wymagań, opisywania przypadków testowych i wykonywania testów. Narzędzie to nosi nazwę Testlink (http://www.teamst.org/) i jest aplikacją webową na licencji Open Source o bardzo rozbudowanej funkcjonalności. Do głównych zalet Testlinka należy zaliczyć dostępność API XML/RPC umożliwiającego pobieranie wyników testów oraz współpracę z wieloma systemami śledzenia błędów. Mimo powyższych zalet aplikacja Testlink posiada też kilka mankamentów, które sprawiają, że nie spełnia wszystkich wymagań klienta. Należy tutaj wymienić mało przyjazny dla użytkownika interfejs, narzucenie modelu procesu testowania niezgodnego z modelem stosowanym w firmie, a także brak integracji z narzędziami do automatyzacji testów.

Ważnymi elementami składowymi środowiska docelowego dla projektowanego oprogramowania są narzędzia takie jak Jira i Hudson. Ich obecność wymusza uwzględnienie na etapie projektowym rozwiązań, które pozwolą na zintegrowanie z nimi tworzonej aplikacji. Konieczne jest umożliwienie testerowi raportowania błędów do Jiry z poziomu aplikacji w przypadku wykrycia błędu podczas testowania, a także zapewnienie funkcjonalności łączenia przypadków testowych i wymagań z odpowiednimi testami automatycznymi wykonywanymi przez Hudsona.

Analiza wymagań użytkownika

Główne wymagania funkcjonalne systemu:

  • Zarządzanie projektami grupującymi wymagania i przypadki testowe dla pojedynczych produktów/modułów oprogramowania wytwarzanych przez firmę
  • Zarządzanie zespołem testerów dla danego projektu (dodawanie/usuwanie użytkowników z projektu)
  • Zarządzanie przypadkami testowymi i wymaganiami (CRUD)
  • Zarządzanie zestawami przypadków testowych i wymagań (CRUD)
  • Przypisywanie wymagań do użytkowników
  • Śledzenie dat i autorów ostatnich modyfikacji w przypadkach testowych i wymaganiach
  • Zarządzanie priorytetami przypadków testowych
  • Automatyczne blokowanie przypadków testowych na czas edycji
  • Integracja modułów zarządzania przypadkami testowymi i wymaganiami w celu umożliwienia tworzenia powiązań między nimi
  • Integracja aplikacji z narzędziem do śledzenia błędów Jira
  • Integracja z serwerem CI Hudson na potrzeby wykonywania testów automatycznych (w tym pobieranie rezultatów tych testów i uwzględnianie ich w raportach)
  • Generowanie raportów informujących o rezultatach testów i postępach prac nad projektem
  • Zarządzanie użytkownikami i ich grupami
  • Przypisywanie ról użytkownikom
  • Możliwość blokowania kont i resetowania haseł użytkowników
  • Zarządzanie profilem użytkownika
  • Panel zbiorczy z informacjami o ostatnich zmianach
  • Wyszukiwanie pełnotekstowe w opisach przypadków i wymagań

Wymagania związane z interfejsem użytkownika:

  • Łatwy w obsłudze interfejs (obsługa drag & drop, multiselect, menu kontekstowe, wygodna nawigacja- pasek umożliwiający szybkie przejście do poprzedniego widoku, menu główne udostępniające najważniejsze funkcje)
  • Sortowanie tabeli przypadków testowych i wymagań
  • Walidacja formularzy
  • Powiadomienia o zmianach w wymaganiach dotyczących danego przypadku testowego
  • Kopiowanie przypadków testowych i wymagań
  • Wydruk przypadków testowych i wymagań

Określenie przypadków oraz scenariuszy użycia

Konto użytkownika:

  1. Rejestracja użytkownika w systemie - nowy użytkownik wchodzi na stronę główną aplikacji, przechodzi do panelu rejestracji i wypełnia standardowy formularz rejestracji, podając takie informacje jak: imię, nazwisko, login, hasło, adres email. Po zwalidowaniu wprowadzonych informacji przez system następuje utworzenie nowego konta w systemie z domyślną rolą REGULAR_USER. Administrator systemu aktywuje konto użytkownika i od tego momentu może on korzystać z systemu.
  2. Logowanie użytkownika do systemu - użytkownik wchodzi na stronę logowania, podaje swój login oraz hasło. Po zweryfikowaniu poprawności danych przez system użytkownik przenoszony jest do widoku panelu zbiorczego aplikacji. Interfejs aplikacji jest spersonalizowany pod kątem roli użytkownika, przynależności do zespołów projektowych i przypisanych wymagań.
  3. Modyfikacja profilu użytkownika - zalogowany użytkownik przechodzi do zakładki ustawień, a następnie do panelu profilu użytkownika. Panel ten umożliwia zmianę danych osobowych, adresu email, hasła, itp. Ponadto użytkownik może zarządzać mechanizmem powiadomień o zmianach w przypisanych mu wymaganiach. Po kliknięciu przycisku 'Zapisz' zweryfikowane dane zostają zapisane w systemie

Konta użytkowników z punktu widzenia administratora:

  1. Zarządzanie kontem użytkownika - użytkownik z prawami administratora przechodzi do zakładki ustawień, a następnie do panelu zarządzania kontami użytkowników. Panel ten udostępnia pełną funkcjonalność CRUD dla kont użytkowników. Oprócz podstawowych operacji jak dodawanie, usuwanie, przeglądanie czy edycja, w szczególności administrator może aktywować konto lub je zablokować, zmienić rolę danego użytkownika, zmienić grupę użytkownika lub zresetować jego hasło. Wszystkie modyfikacje są walidowane.
  2. Zarządzanie grupami użytkowników - użytkownik z prawami administratora przechodzi do zakładki ustawień, a następnie do panelu zarządzania grupami użytkowników. Podobnie jak w poprzednim przypadku ma możliwość wykonania wszystkich operacji składających się na przypadek CRUD.

Projekty i zespoły:

  1. Zarządzanie projektami - użytkownik przechodzi do zakładki projektów, a następnie otwiera panel zarządzania portfolio projektów, w którym może dodać, usunąć lub zmodyfikować dowolny projekt. Dodatkowo panel ten umożliwia wybranie aktywnego projektu, czyli tego, z którego przypadki testowe i wymagania mają wyświetlać się w pozostałych widokach.
  2. Zarządzanie zespołem - użytkownik przechodzi do panelu zarządzania zespołem dla aktywnego projektu, w którym ma możliwość przypisania/usunięcia dowolnego użytkownika w systemie do/z projektu. Przypisanie użytkownika do projektu skutkuje tym, że na swoim panelu zbiorczym będzie on widział informacje dotyczące tego projektu, a także tym, że będzie otrzymywał powiadomienia o wszelkich ważnych zmianach w projekcie.

Wymagania i ich zestawy:

  1. Zarządzanie zestawami wymagań - użytkownik przechodzi do zakładki budowania testów, a następnie otwiera panel zarządzania wymaganiami. Panel ten umożliwia zarządzanie zestawami wymagań oraz samymi wymaganiami. Samo zarządzanie zestawami wymagań odbywa się z poziomu menu kontekstowego komponentu-drzewka, reprezentującego hierarchię wymagań i ich zestawów. Użytkownik może dodać zestaw, usunąć go lub zmienić mu nazwę.
  2. Tworzenie/edycja wymagań - użytkownik znajdując się w panelu zarządzania wymaganiami widzi wspomniane drzewko oraz tabelę wyświetlającą wymagania dla aktualnie wybranego zestawu. Drzewko umożliwia kopiowanie wymagań i przeciąganie ich pomiędzy zestawami metodą 'Drag & Drop'. Z poziomu tego widoku użytkownik może utworzyć nowe wymaganie lub przejść do widoku edycji wymagania (po dwukrotnym jego kliknięciu). Obie akcje powodują wyświetlenie formularza umożliwiającego edycję wymagania, czyli m.in.: jego nazwy, opisu, statusu, użytkownika odpowiedzialnego za przetestowanie wymagania.
  3. Usuwanie wymagań - usuwanie wymagań odbywa się z poziomu drzewka (poprzez wybranie opcji usuń z menu kontekstowego) lub z poziomu tabeli wymagań. Pewnym ułatwieniem jest umożliwienie zaznaczenia wielu wymagań i usunięcia ich jednym kliknięciem (multiselect). Każda operacja usunięcia musi zostać potwierdzona.
  4. Przeglądanie i filtrowanie wymagań - specjalne pole w panelu zarządzania wymaganiami umożliwia filtrowanie wyświetlanych wymagań. Użytkownik wybiera z dostępnej listy opcji, te które odpowiadają interesującym go wymaganiom, a system filtruje wyświetlane rekordy zgodnie z wybranymi ograniczeniami.

Przypadki testowe i ich zestawy:

  1. Zarządzanie zestawami przypadków testowych - użytkownik przechodzi do panelu zarządzania przypadkami testowymi w zakładce budowania testów. Zarządzanie zestawami przypadków testowych odbywa się w taki sam sposób jak zarządzanie zestawami wymagań. Krótko mówiąc- nudny CRUD.
  2. Tworzenie/edycja przypadków testowych - przejście do formularza edycji/tworzenia nowego przypadku testowego odbywa się analogicznie jak w przypadku wymagań. Przejście do trybu edycji powoduje zablokowanie przypadku testowego, dzięki czemu inni użytkownicy nie mają możliwości edycji tego przypadku. Po wyświetleniu formularza użytkownik może zmodyfikować takie właściwości przypadku testowego jak: nazwa, priorytet czy prerekwizyty. Oprócz tego może on oczywiście dodawać kroki procedury testowej oraz oczekiwane rezultaty. Zapisanie zmian powoduje ich walidację oraz zapisanie w bazie.
  3. Przypisywanie wymagań do przypadków testowych - znajdując się w widoku edycji przypadku użytkownik korzystając z dwóch list dodaje do przypadku testowego wymagania pokrywane przez dany przypadek. Do wyboru ma wymagania zdefiniowane dla aktywnego projektu.
  4. Usuwanie przypadków testowych - użytkownik przechodzi do panelu zarządzania przypadkami testowymi i po wybraniu przypadku (w drzewku projektu lub w tabeli) naciska przycisk 'Usuń'. Zostaje wyświetlony komunikat z prośbą o potwierdzenie operacji. Pozytywna odpowiedź skutkuje usunięciem wskazanych rekordów z bazy.
  5. Przeglądanie przypadków testowych - przeglądanie przypadków testowych odbywa się w panelu zarządzania przypadkami testowymi. Aby wykonywanie tej czynności było wygodne, przeglądanie odbywa się z wykorzystaniem drzewa reprezentującego hierarchię projektu oraz tabeli wyświetlającej przypadki z danego zestawu przypadków. Tabela ta wyświetla m.in. informacje o autorze każdego przypadku, dacie modyfikacji, stanie (zablokowany/niezablokowany) i ew. użytkowniku, który aktualnie edytuje przypadek. Po kliknięciu przypadku zostaje wyświetlony bardziej szczegółowy widok, który dodatkowo wyświetla informacje o powiązanych wymaganiach.

Raporty, panel zbiorczy, wyszukiwanie:

  1. Przeglądanie raportów dot. postępów projektu - użytkownik otwiera zakładkę panelu zbiorczego, w następstwie zostaje wyświetlony widok zawierający raporty dla aktywnego projektu, tj.: raport w postaci wykresu błędów w testach na przestrzeni czasu, stanu pokrycia wymagań testami, ilości przeprowadzonych testów.
  2. Przeglądanie raportów dot. aktywności użytkowników - w panelu zbiorczym użytkownik otwiera widok raportów na temat aktywności użytkowników w danym projekcie. Widok ten prezentuje ostatnio zmienione lub dodane wymagania i testy, wykryte błędy, komentarze użytkowników, itd.
  3. Przeszukiwanie systemu - użytkownik wpisuje szukaną frazę w pole tekstowe w głównym menu aplikacji i naciska przycisk 'Szukaj'. W odpowiedzi system wyświetla listę wymagań i przypadków testowych, których opisy zawierają daną frazę.

Testowanie:

  1. Wykonywanie testów - użytkownik otwiera zakładkę wykonywania testów. System wyświetla widok podobny jak w przypadku przeglądania przypadków testowych, z tą różnicą, że zamiast edycji umożliwia przejście do trybu wykonywania testu. Użytkownik wybiera z listy jeden z przypadków testowych i przechodzi do trybu testowania. Nowy widok zawiera listę kroków danego testu wraz z oczekiwanymi rezultatami, a także komponenty umożliwiające zapisanie wyniku każdego z kroków, dodawanie komentarzy czy raportowanie błędów w systemie Jira. Użytkownik wykonuje kolejne kroki testu, przy każdym z nich zaznaczając czy wykonał się poprawnie. Pomyślne wykonanie wszystkich kroków sprawia, że status testu zmienia się na DONE, w przeciwnym wypadku zostaje ustawiony status FAILED. Należy zaznaczyć, że wystąpienie błędu wymusza na użytkowniku dodanie komentarza, który dokładnie go opisuje. Dodatkowo pojawia się komunikat, który mówi, że zgłoszenie błędu systemie Jira jest zalecane, aczkolwiek niekonieczne.

Identyfikacja funkcji

Podstawowe funkcje realizowane przez system na bazie danych będą skupiały się wokół przechowywania i udostępniania informacji na temat:

  • kont użytkowników
  • grup użytkowników
  • projektów
  • wymagań i ich hierarchii
  • przypadków testowych i ich hierarchii (w tym powiązań pomiędzy wymaganiami i przypadkami testowymi)
  • rezultatów testów

Analiza hierarchii funkcji projektowanej aplikacji

Budowa i analiza diagramu przepływu danych

Diagram kontekstowy

Diagram wstępny

1. Analiza projektu

2. Zarządzanie projektami

3. Wykonywanie testów

4. Budowanie testów

5. Zarządzanie kontem

6. Zarządzanie użytkownikami

Wybór encji (obiektów) i ich atrybutów

W systemie zidentyfikowano następujące encje:

  • Projekt
  • Zestaw przypadków testowych
  • Zestaw wymagań
  • Przypadek testowy
  • Kroki przypadku testowego
  • Wymaganie
  • Użytkownik
  • Grupa użytkowników

Atrybuty tych encji oraz relacje pomiędzy encjami zaprezentowano na poniższym diagramie ERD.

Projektowanie powiązań (relacji) pomiędzy encjami

Projekt diagramów STD

Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów, etc. w oparciu o zdefiniowany diagram ERD

Projekt SQL:

Schemat bazy danych

Należy w tym miejscu dodać, że dla każdego klucza głównego w bazie danych automatycznie tworzony jest indeks typu B-tree, co jest domyślnym zachowaniem systemu PostgreSQL.

Słowniki danych

Tabela REQUIREMENT_SETS:

  • RQS_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • RQS_NAME ciąg znaków, długość < 50, wymagane, nazwa zestawu
  • RQS_PROJECT - liczba całkowita, wymagane, projekt zawierający

Tabela PROJECTS:

  • PR_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • PR_NAME - ciąg znaków, długość < 20, wymagane, nazwa projektu

Tabela GROUPS:

  • GR_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • GR_NAME - ciąg znaków, długość < 50, wymagane, nazwa grupy

Tabela STEPS:

  • ST_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • ST_NR - liczba całkowita, wymagane, numer kroku
  • ST_ACTION - tekst, opis kroku
  • ST_RESULT - tekst, opis otrzymanego rezultatu
  • ST_TESTCASE - liczba całkowita, wymagane, przypadek testowy kroku
  • ST_EXPECTED_RESULT - tekst, oczekiwany wynik testu
  • ST_JIRA_ISSUE - tekst, URL do issue w systemie Jira

Tabela REQUIREMENTS:

  • RQ_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • RQ_STATUS - ciąg znaków, długość < 15, wymagane, status wymagania [ACCEPTED|REJECTED|NEW]
  • RQ_CASES_NR - liczba całkowita, wymagane, liczba pokrywających przypadków testowych
  • RQ_ASSIGNEE - liczba całkowita, wymagane, osoba przypisana do wymagania
  • RQ_CREATED - timestamp, wymagane, data utworzenia
  • RQ_REQUIREMENT_SET - liczba całkowita, wymagane, zawierający zestaw
  • RQ_CONTENT - tekst, opis wymagania
  • RQ_NAME - ciąg znaków, długość < 50, wymagane, nazwa
  • RQ_AUTHOR - liczba całkowita, wymagane, autor
  • RQ_UPDATED - timestamp, data modyfikacji

Tabela TESTCASES:

  • TC_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • TC_BLOCKED - boolean, wymagane, stan [ZABLOKOWANY|DOSTĘPNY]
  • TC_UPDATED - timestamp, wymagane, data modyfikacji
  • TC_TESTCASE_SET - liczba całkowita, wymagane, zestaw przypadków
  • TC_BLOCKED_BY - liczba całkowita, użytkownik edytujący
  • TC_NAME - ciąg znaków, długość < 50, wymagane, nazwa
  • TC_PRIORITY - ciąg znaków, długość < 15, wymagane, priorytet [HIGH|MEDIUM|LOW]
  • TC_PREREQUISITES - tekst, prerekwizyty
  • TC_AUTHOR - liczba całkowita, wymagane, autor

Tabela USERS:

  • USR_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • USR_NAME - ciąg znaków, długość < 20, wymagane, imię
  • USR_SURNAME - ciąg znaków, długość < 30, wymagane, nazwisko
  • USR_LOGIN - ciąg znaków, długość < 30, wymagane, login
  • USR_EMAIL - ciąg znaków, długość < 30, wymagane, adres email
  • USR_ROLE - ciąg znaków, długość < 20, wymagane, rola [REGULAR_USER|ADMIN]
  • USR_GROUP - liczba całkowita, grupa
  • USR_ACTIVE - boolean wymagane, stan [ACTIVE|INACTIVE]
  • USR_PASSWORD - tekst wymagane, hash hasła

Tabela TESTCASE_SETS:

  • TCS_ID - liczba całkowita, wymagane, automatycznie generowany identyfikator
  • TCS_NAME - ciąg znaków, długość < 50, wymagane, nazwa
  • TCS_PROJECT - liczba całkowita, projekt zawierający

Analiza zależności funkcyjnych i normalizacja tabel

Pierwsza postać normalna (1NF)

Wszystkie atrybuty encji w przedstawionym modelu są atomiczne, a więc baza danych spełnia warunek pierwszej postaci normalnej.

Druga postać normalna (2NF)

Aby spełniona była druga postać normalna wszystkie atrybuty niekluczowe encji muszą zależeć od całego klucza głównego tej encji. W przedstawionym schemacie wszystkie tabele z wyjątkiem PROJECT_USERS i TESTCASE_REQUIREMENTS posiadają klucz główny prosty, a więc warunek ten jest spełniony. Z kolei tabele PROJECT_USERS oraz TESTCASE_REQUIREMENTS są typowymi tabelami asocjacyjnymi i nie posiadają atrybutów niekluczowych.

Trzecia postać normalna (3NF)

Baza danych spełnia trzecią postać normalną. W żadnej z encji opracowanego modelu nie występują relacje tranzytywne, wszystkie atrybuty zależą bezpośrednio od klucza głównego.

Projektowanie operacji na danych

W projekcie zostanie wykorzystane rozwiązanie ORM Hibernate, które przejmuje od nas odpowiedzialność za operowanie na bazie danych. Poniżej przedstawiona została przykładowa implementacja klasy-encji, reprezentującej przypadek testowy:

    package pl.edu.agh.testo.data;

    @Entity
    @SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "testcase_seq")
    public class TestCase implements Serializable {

	@Id
        @GeneratedValue(strategy = GenerationType.AUTO, generator = "idgen")
        private Long testCaseId;
        private String name;
        private boolean blocked;
        private Date created;
        private Date updated;
        private TestCasePriority priority;
        private String prerequisites;
    
        @ManyToOne
        private AppUser author;
    
        @ManyToOne 
        private TestCaseSet testCaseSet;
    
        @ManyToOne
        private AppUser blockedBy;
    
        @ManyToMany
        @JoinTable(
            name="testcase_requirement",
    	    joinColumns=@JoinColumn(name="testcase_id"),
    	    inverseJoinColumns=@JoinColumn(name="requirement_id")
        )
        private Set<Requirement> requirements;
    
        @OneToMany(mappedBy = "testCase", cascade = CascadeType.ALL)
        @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
        @JoinColumn(name = "testCaseId")
        private Set<Step> steps;

	public TestCase() {
        }
    
	public Long getTestCaseId() {
		return testCaseId;
	}

	//getters and setters...
    }

Reprezentatywne przykłady zapytań SQL generowanych przez Hibernate:

a) pobieranie listy projektów dla panelu zarządzania projektami:

select this_.projectId as projectId0_0_, this_.name as name0_0_ from Project this_ order by this_.projectId asc limit ?

b) aktualizacja nazwy projektu

update Project set name=? where projectId=?

c) tworzenie nowego projektu

insert into Project (name, projectId) values (?, ?)

d) pobranie listy wymagań dla panelu zarządzania wymaganiami

select this_.requirementId as requirem1_4_5_, this_.assignee_appUserId as assignee8_4_5_, this_.author_appUserId as author9_4_5_, this_.content as content4_5_, 
this_.created as created4_5_, this_.name as name4_5_, this_.numberOfCases as numberOf5_4_5_, this_.requirementSetId as require10_4_5_, this_.requirementStatus
 as requirem6_4_5_, this_.updated as updated4_5_, appuser3_.appUserId as appUserId6_0_, appuser3_.active as active6_0_, appuser3_.email as email6_0_, 
appuser3_.group_userGroupId as group8_6_0_, appuser3_.login as login6_0_, appuser3_.name as name6_0_, appuser3_.password as password6_0_, appuser3_.role as 
role6_0_, usergroup4_.userGroupId as userGrou1_5_1_, usergroup4_.name as name5_1_, appuser5_.appUserId as appUserId6_2_, appuser5_.active as active6_2_, 
appuser5_.email as email6_2_, appuser5_.group_userGroupId as group8_6_2_, appuser5_.login as login6_2_, appuser5_.name as name6_2_, appuser5_.password as 
password6_2_, appuser5_.role as role6_2_, rs1_.requirementSetId as requirem1_2_3_, rs1_.name as name2_3_, rs1_.projectId as projectId2_3_, project7_.projectId 
as projectId0_4_, project7_.name as name0_4_ 
from Requirement this_ left outer join AppUser appuser3_ on this_.assignee_appUserId=appuser3_.appUserId 
left outer join UserGroup usergroup4_ on appuser3_.group_userGroupId=usergroup4_.userGroupId 
left outer join AppUser appuser5_ on this_.author_appUserId=appuser5_.appUserId 
inner join RequirementSet rs1_ on this_.requirementSetId=rs1_.requirementSetId 
left outer join Project project7_ on rs1_.projectId=project7_.projectId where rs1_.projectId=? 
order by this_.requirementId asc limit ?

e) modyfikacja wymagania

update Requirement set assignee_appUserId=?, author_appUserId=?, content=?, created=?, name=?, numberOfCases=?, requirementSetId=?, requirementStatus=?, 
updated=? where requirementId=?

f) usunięcie wymagania

delete from testcase_requirement where requirementId=?
delete from Requirement where requirementId=?

Jak widać zapytania generowane przez Hibernate nie zawsze są optymalne. Przykładowo- pobranie obiektu klasy Requirement pociąga za sobą pobranie całej struktury obiektów powiązanych, a co za tym idzie wykonanie pięciu złączeń, pomimo, że nie potrzebujemy wszystkich zawartych w nich danych. Jest to bolączka wszystkich rozwiązań ORM. Pewną rekompensatą jest zastosowanie cache'u. Inną metodą łagodzenia problemu są różne fetching strategies, które definiuje Hibernate (np. domyślną strategią dla kolekcji jest lazy fetching dzięki czemu kolekcje ładowane są dopiero wówczas kiedy są potrzebne).

Implementacja bazy danych

Wykorzystanie w projekcie biblioteki Hibernate sprawiło, że implementacja bazy danych sprowadziła się do skonfigurowania samego Hibernate'a oraz utworzenia modelu danych opisanego za pomocą adnotacji zdefiniowanych w standardzie JPA. Zastosowanie rozwiązania ORM pozwoliło na znaczne przyspieszenie prac i uwolniło nas od konieczności utrzymywania schematu bazy zgodnego z aktualnym modelem danych aplikacji.

Poniższy listing przedstawia kod klasy HibernateUtil odpowiedzialnej za konfigurację połączenia z bazą oraz zarządzanie instancją klasy SessionFactory:

public class HibernateUtil {

    private static final SessionFactory sessionFactory;

    static {
        try {
            AnnotationConfiguration cnf = new AnnotationConfiguration();
            cnf.setProperty(Environment.DRIVER, "org.postgresql.Driver");
            cnf.setProperty(Environment.URL, "jdbc:postgresql://localhost:5432/tessto");
            cnf.setProperty(Environment.USER, "user");
            cnf.setProperty(Environment.PASS, "password");
            cnf.setProperty(Environment.DIALECT, PostgreSQLDialect.class.getName());
            cnf.setProperty(Environment.SHOW_SQL, "true");
            cnf.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
            cnf.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
            cnf.addAnnotatedClass(Project.class);
            cnf.addAnnotatedClass(TestCaseSet.class);
            cnf.addAnnotatedClass(RequirementSet.class);
            cnf.addAnnotatedClass(TestCase.class);
            cnf.addAnnotatedClass(Requirement.class);
            cnf.addAnnotatedClass(UserGroup.class);
            cnf.addAnnotatedClass(AppUser.class);
            cnf.addAnnotatedClass(Step.class);
            sessionFactory = cnf.buildSessionFactory();
        } 
        catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
    
}

Opcja cnf.setProperty(Environment.HBM2DDL_AUTO, „create-drop”) powoduje automatyczne wygenerowanie poleceń SQL budujących strukturę bazy i wykonanie ich na bazie.

POJO reprezentujące wymaganie wraz z adnotacjami:

@Entity
@SequenceGenerator(initialValue = 1, name = "idgen", sequenceName = "requirement_seq")
public class Requirement implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "idgen")
    private Long requirementId;
    private String name;
    private String content;
    private RequirementStatus requirementStatus;
    private int numberOfCases;
    private Date created;
    private Date updated;
    
    @ManyToOne 
    private AppUser author;
    
    @ManyToOne
    private AppUser assignee;
    
    @ManyToOne
    @JoinColumn(name = "requirementSetId")
    private RequirementSet requirementSet;
    
    @ManyToMany
    @JoinTable(
    		name="testcase_requirement",
    		joinColumns=@JoinColumn(name="requirementId"),
    		inverseJoinColumns=@JoinColumn(name="testCaseId")
    )
    private Set<TestCase> testCases;
    
    // getters and setters...
} 

Jak widać Hibernate oferuje szereg ułatwień jak np. automatyczną obsługę relacji many-to-many. Wykorzystując adnotację @ManyToMany nie musimy sami tworzyć tabel asocjacyjnych- robi to za nas Hibernate.

Zdefiniowanie interfejsów do prezentacji, edycji i obsługi danych

Zarządzanie projektami

Panel ten odpowiada stanowi 'Zarządzanie projektami' na diagramie STD i przypadkowi użycia 'Projekty i zespoły: Zarządzanie projektami'.

Edycja projektu

Panel ten odpowiada stanowi 'Edycja projektu' na diagramie STD i przypadkowi użycia 'Projekty i zespoły: Zarządzanie projektami'.

Przeglądanie przypadków testowych

Panel ten odpowiada stanowi 'Budowanie testów - listy wymagań i przypadków testowych (Test Workbench)' na diagramie STD i przypadkom użycia 'Zarządzanie zestawami przypadków testowych', 'Tworzenie/edycja przypadków testowych', 'Usuwanie przypadków testowych' oraz 'Przeglądanie przypadków testowych' z grupy 'Przypadki testowe i ich zestawy'.

Podgląd przypadku testowego

Panel ten odpowiada stanowi 'Budowanie testów - listy wymagań i przypadków testowych (Test Workbench - podgląd przypadku)' na diagramie STD i przypadkom użycia 'Zarządzanie zestawami przypadków testowych' oraz 'Przeglądanie przypadków testowych' z grupy 'Przypadki testowe i ich zestawy'.

Edycja przypadku testowego

Panel ten odpowiada stanowi 'Formularz tworzenia/edycji przypadków testowych' na diagramie STD i i przypadkom użycia 'Zarządzanie zestawami przypadków testowych', 'Tworzenie/edycja przypadków testowych' oraz 'Przypisywanie wymagań do przypadków testowych' z grupy 'Przypadki testowe i ich zestawy'.

Przeglądanie wymagań

Panel ten odpowiada stanowi 'Budowanie testów - listy wymagań i przypadków testowych (Test Workbench)' na diagramie STD i przypadkom użycia 'Zarządzanie zestawami wymagań', 'Usuwanie wymagań' oraz 'Przeglądanie i filtrowanie wymagań' z grupy 'Wymagania i ich zestawy'.

Podgląd wymagania

Panel ten odpowiada stanowi 'Budowanie testów - listy wymagań i przypadków testowych (Test Workbench - podgląd wymagania)' na diagramie STD i przypadkom użycia 'Zarządzanie zestawami wymagań' oraz 'Przeglądanie i filtrowanie wymagań' z grupy 'Wymagania i ich zestawy'.

Edycja wymagania

Panel ten odpowiada stanowi 'Formularz tworzenia/edycji wymagań' na diagramie STD i przypadkom użycia 'Zarządzanie zestawami wymagań' oraz 'Tworzenie/edycja wymagań' z grupy 'Wymagania i ich zestawy'.

Uruchamianie i testowanie aplikacji/ Wdrażanie systemu do użytkowania

Aplikacja została stworzona z wykorzystaniem frameworka Vaadin bazującego na technologii GWT. Paczka instalacyjna ma więc postać archiwum WAR obsługiwanego przez dowolny kontener serwletów (Tomcat, Jetty, itp.). Do zainstalowania aplikacji wymagane są następujące elementy:

  • kontener serwletów (testowane na kontenerze Apache Tomcat 7.0.14)
  • serwer bazy danych (testowane na PostgreSQL 9.0.4)

W razie konieczności skalowania aplikacji można wykorzystać przykładowo serwer HTTP Apache z modułem mod_jk, działający w charakterze proxy/load balancera dla kilku instancji kontenerów.

Wdrożona instancja aplikacji dostępna jest pod adresem http://lukasz.sanek.org.pl/tessto

Zapewnienie dokumentacji technicznej i użytkowej

Dokumentacja powinna zawierać:

  • opis interfejsu aplikacji z punktu widzenia zwykłego użytkownika
  • opis zarządzania projektami z punktu widzenia użytkownika o uprawnieniach administratora
  • instrukcję instalacji/aktualizacji oraz konfiguracji aplikacji dla administratora systemu

Rozwijanie i modyfikowanie aplikacji

W chwili obecnej aplikacja pozwala na wykonywanie podstawowych czynności związanych z zarządzaniem projektami, wymaganiami i przypadkami testowymi. Na dalszych etapach rozwoju należałoby rozważyć rozbudowanie jej o takie funkcjonalności jak:

  • Wersjonowanie przypadków testowych i wymagań
  • Integracja z JIRĄ i Hudsonem
  • Rozbudowane raporty o stanie testów
  • Automatyczne estymacje czasu wykonywania poszczególnych przypadków testowych bazujące na danych historycznych
  • Wyszukiwanie pełnotekstowe w opisach przypadków i wymagań
  • Dołączanie screenshotów do opisów błędów (wbudowane narzędzie do wykonywania zrzutów interesujących obszarów ekranu)

Opracowanie doświadczeń wynikających z realizacji projektu

Jak już zostało wspomniane aplikacja została stworzona z wykorzystaniem frameworka Vaadin, który powstał z myślą o budowaniu aplikacji RIA w Javie. O wyborze technologii zadecydowały takie czynniki jak: obszerna dokumentacja, łatwość wdrożenia się w technologię (dla osób, które korzystały już ze Swinga/AWT lub SWT), aktywna społeczność i możliwość tworzenia aplikacji AJAX bez konieczności poznawania technologii JavaScript. Decyzja okazała się trafna- w krótkim czasie udało się zapoznać z technologią i zrealizować projekt bez większych problemów, w głównej mierze dzięki dużej liczbie dostępnych przykładów i wsparciu ze strony społeczności. Obszerne portfolio gotowych komponentów, a także łatwość wprowadzania własnych modyfikacji przyczyniły się do stworzenia produktu o wysokim poziomie użyteczności.

Należy także wspomnieć o bibliotece Hibernate, której wykorzystanie pozwoliło na znaczne uproszczenie pracy z warstwą modelu i jego persystencją w bazie danych. Dodatkowy narzut czasowy związany z koniecznością poznania kolejnej technologii w ostatecznym rozrachunku okazał się trafioną inwestycją.

Wykaz literatury

  1. „Book of Vaadin” (http://vaadin.com/pl/book)
  2. BlackBeltFactory: Vaadin Fundamentals (http://www.blackbeltfactory.com/ui#CoursePage/12215164)

Załączniki

2011/06/03 18:47
pl/dydaktyka/ztb/2011/projekty/ha.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0