diff --git a/parts/01_patterns.tex b/parts/01_patterns.tex index e41fff8..9ac5eea 100644 --- a/parts/01_patterns.tex +++ b/parts/01_patterns.tex @@ -528,102 +528,4 @@ public class DocumentDTO implements Serializable { \item kapselt und versteckt \item nimmt Komplexität \item steigert Effizienz da weniger Aufrufe über Remotegrenze -\end{itemize} -\section{Page-Object-Pattern} -\begin{itemize} - \item stellt Screens der Web-App als Reihe von Objekten dar - \item tatsächlich werden nicht alle Seiten sondern wesentliche Elemente in Objekte gekapselt - \item eine HTML Seite wird so mitunter mit mehreren Objekten dargestellt (z.B. Header und Footer Page Object) - \item Das Page Objekt Design eignet sich besonders gut um Selenium Tests umzusetzen - \item Mittels der Page Objekte kann HTML Code verändert werden (Verkapselung) - \item ermöglichen die Modellierung der Benutzeroberfläche für Tests - \item reduziert Code duplication - \item verbessert Testwartbarkeit und macht Tests robuster -\end{itemize} -\subsection{Page Object Pattern lt. Zahnlücke} -\begin{itemize} -\item Trennung zwischen Testmethode und Page Code -\item Je Page eine Klasse mit Services / Operationen -\item Return einer Operation ist ein PageObject -\item Einfachere Wartbarkeit (Kapselung in PageObject) -\end{itemize} -\begin{figure}[!htp] - \centering - \includegraphics[width=0.8\textwidth]{pics/page-object.png} -\end{figure} -\subsection{Beispiel aus dem Projekt} -\subsubsection{Integration GUI Test mit Selenium} -\begin{minted}[linenos,breaklines=true]{java} -package at.fhj.swd.psoe.gui.pages; - -import org.openqa.selenium.By; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import java.util.List; - -public class DocumentsListPage extends AbstractPage { - private List list; - - public DocumentsListPage(WebDriver driver) { - super(driver); - } - public List getList() { - list = this.getDriver().findElements(By.xpath("//*[@id=\"documents:comdoctable_data\"]")); - return list; - } - -} -\end{minted} -\subsubsection{Durch Selenium getestetes Page Objekt} -\begin{minted}[linenos,breaklines=true]{java} - package at.fhj.swd.psoe.gui; - - import at.fhj.swd.psoe.JdbcTestHelper; - import at.fhj.swd.psoe.gui.pages.*; - import org.junit.After; - import org.junit.Assert; - import org.junit.Before; - import org.junit.Test; - - import java.io.IOException; - import java.sql.SQLException; - import java.util.stream.Collectors; - - public class ShowDocumentsListITCase extends AbstractChromeTest { - final private String roleName = "ADMIN"; - private LoginPage loginPage; - private WelcomePage welcomePage; - private DocumentsListPage documentsListPage; - private String baseUrl = "http://localhost:8080/chr-krenn-fhj-ws2018-swd16-pse"; - private static final JdbcTestHelper JDBC_HELPER = new JdbcTestHelper(); - - @Before - @Override - public void setUp() { - super.setUp(); - JDBC_HELPER.executeSqlScript( - "src/test/resources/sql/DocumentServiceITCase-addDocument.sql"); - loginPage = new LoginPage(this.driver, baseUrl, 60); - welcomePage = loginPage.login("testdocument@swd.com", "admin"); - CommunitiesPage communitiesPage = welcomePage.openCommunitiesPage(); - CommunityPage communityPage = communitiesPage.openCommunityPage(); - documentsListPage = communityPage.openDocumentListPage(); - } - - @Test - public void testTwoDocumentsListed() { - String content = documentsListPage.getList().stream().map(x -> x.getText()).collect(Collectors.joining()); - Assert.assertTrue(content.contains("documentuser123")); - Assert.assertTrue(content.contains("DocumentITCase1")); - Assert.assertTrue(content.contains("DocumentITCase2")); - } - - @After - @Override - public void tearDown() { - super.tearDown(); - JDBC_HELPER.executeSqlScript( - "src/test/resources/sql/DocumentServiceITCase-deleteDocument.sql"); - } - } -\end{minted} \ No newline at end of file +\end{itemize} \ No newline at end of file diff --git a/parts/03_config.tex b/parts/03_config.tex index f73bea1..6766c2c 100644 --- a/parts/03_config.tex +++ b/parts/03_config.tex @@ -471,17 +471,181 @@ public void saveUser(UserDTO userDTO) { } \end{minted} \section{Tests} +\begin{itemize} + \item Ziel der Tests ist es, 100\% Codecoverage im Service-Layer zu erreichen (Anforderung für unser Projekt), + \item Private und Protected-Methoden müssen per se nicht getestet werden (Rule of Thumb),Wege zum erfolgreichen Test: + \begin{itemize} + \item Access-Modifier der Methoden auf public (public static) ändern, + \item Extrahieren der Methoden in neue Klassen, + \item Notfalls Package-Sichtbarkeit in Methode, wenn diese privat bleiben muss, Tests aber unbedingt notwendig sind. + \end{itemize} +\end{itemize} + + + + \subsection{Testpyramide} -\begin{figure}[h] +\begin{figure}[ht!] \centering \includegraphics[width=0.9\linewidth]{pics/testpyramide} \caption{} \label{fig:testpyramide} \end{figure} \subsection{Unit} -\subsection{Integration} -\subsection{Selenium bzw. GUI} +\begin{itemize} + \item Im Build-Cycle werden zuerst Unit-Tests ausgeführt, + \item sie befinden sich im Projekt im Ordner \textit{src/test/at/fhj/swd/psoe/service/*Test.java}, + \item ein Unit-Test muss jede Methode der Service-Klasse testen + \item Mockito imitiert die Methoden, die von der Datenbank abhängen, da diese zu diesem Zeitpunkt noch nicht zur Verfügung steht (Build-Cycle => Compile - Unit-Tests) + \item Im Unit-Test wird jeweils die kleinste Einheit getestet + \item Exceptions einfach mit Mockito werfen und testen, ob sie geworfen wurden +\end{itemize} +\begin{minted}[linenos,breaklines=true]{java} +@Test(expected = ServiceException.class) +public void testGetCommunityByUserMessagesDAOException() +{ +Mockito.when(this.userPrincipal.getId()).thenReturn(-1L); +Mockito.when(this.communityService.loadAllCommunitiesByUser(-1L)).thenThrow(new DaoException(new RuntimeException())); +this.activitystreamService.getCommunityByUserMessages(); +} +\end{minted} +\begin{minted}[linenos,breaklines=true]{java} +@Test +public void getDocumentsFromCommunity_ShouldReturnDocuments() { + Community community = Mockito.mock(Community.class); + Mockito.when(community.getId()).thenReturn(DOCUMENTID); + Documentlibrary doclib = Mockito.mock(Documentlibrary.class); + + Mockito.when(community.getDocumentlibrary()).thenReturn(doclib); + Mockito.when(doclib.getCommunity()).thenReturn(community); + User user = Mockito.mock(User.class); + + Mockito.when(communityDAO.findById(community.getId())).thenReturn(community); + + List documents = prepareTwoDocuments(doclib,user); + Mockito.when(documentDAO.findByCommunity(community)).thenReturn(documents); + + List documentsDTO = documentService.getDocumentsFromCommunity(community.getId()); + + Assertions.assertThat(documentsDTO) + .usingElementComparatorIgnoringFields("user") + .containsExactlyInAnyOrder(DocumentMapper.toDTO(documents.get(0)), DocumentMapper.toDTO(documents.get(1))); +} +\end{minted} +\subsection{Integration Tests}%TODO Wolfimajer - moch fertig , bi +\begin{itemize} + \item testen alle Komponenten mit (Datenbank) + \item werden im Build-Cycle erst nach dem Deployen des war-Files ausgeführt (laufende Applikation) + \item In unserem Projekt kommt das Plugin \textit{failsafe} zum Einsatz + \item Datenbankscripts werden separat zu den anderen Scripts ausgeführt (Datenbank vorbereiten und auf den alten Stand zurückbringen) + \item + \begin{figure}[h] + \centering + \includegraphics[width=0.7\linewidth]{pics/test_structure} + \caption{} + \label{fig:teststructure} + \end{figure} + \end{itemize} +\subsection{GUI-Test} +\subsubsection{Page Object Pattern} +\begin{itemize} + \item stellt Screens der Web-App als Reihe von Objekten dar + \item tatsächlich werden nicht alle Seiten sondern wesentliche Elemente in Objekte gekapselt + \item eine HTML Seite wird so mitunter mit mehreren Objekten dargestellt (z.B. Header und Footer Page Object) + \item Das Page Objekt Design eignet sich besonders gut um Selenium Tests umzusetzen + \item Mittels der Page Objekte kann HTML Code verändert werden (Verkapselung) + \item ermöglichen die Modellierung der Benutzeroberfläche für Tests + \item reduziert Code duplication + \item verbessert Testwartbarkeit und macht Tests robuster +\end{itemize} +\subsection{Page Object Pattern lt. Zahnlücke} +\begin{itemize} + \item Trennung zwischen Testmethode und Page Code + \item Je Page eine Klasse mit Services / Operationen + \item Return einer Operation ist ein PageObject + \item Einfachere Wartbarkeit (Kapselung in PageObject) +\end{itemize} +\begin{figure}[!htp] + \centering + \includegraphics[width=0.8\textwidth]{pics/page-object.png} +\end{figure} +\subsection{Beispiel aus dem Projekt} +\subsubsection{Integration GUI Test mit Selenium} +\begin{minted}[linenos,breaklines=true]{java} +package at.fhj.swd.psoe.gui.pages; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import java.util.List; + +public class DocumentsListPage extends AbstractPage { +private List list; + +public DocumentsListPage(WebDriver driver) { +super(driver); +} +public List getList() { +list = this.getDriver().findElements(By.xpath("//*[@id=\"documents:comdoctable_data\"]")); +return list; +} + +} +\end{minted} +\subsubsection{Durch Selenium getestetes Page Objekt} +\begin{minted}[linenos,breaklines=true]{java} +package at.fhj.swd.psoe.gui; + +import at.fhj.swd.psoe.JdbcTestHelper; +import at.fhj.swd.psoe.gui.pages.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.stream.Collectors; + +public class ShowDocumentsListITCase extends AbstractChromeTest { +final private String roleName = "ADMIN"; +private LoginPage loginPage; +private WelcomePage welcomePage; +private DocumentsListPage documentsListPage; +private String baseUrl = "http://localhost:8080/chr-krenn-fhj-ws2018-swd16-pse"; +private static final JdbcTestHelper JDBC_HELPER = new JdbcTestHelper(); + +@Before +@Override +public void setUp() { +super.setUp(); +JDBC_HELPER.executeSqlScript( +"src/test/resources/sql/DocumentServiceITCase-addDocument.sql"); +loginPage = new LoginPage(this.driver, baseUrl, 60); +welcomePage = loginPage.login("testdocument@swd.com", "admin"); +CommunitiesPage communitiesPage = welcomePage.openCommunitiesPage(); +CommunityPage communityPage = communitiesPage.openCommunityPage(); +documentsListPage = communityPage.openDocumentListPage(); +} + +@Test +public void testTwoDocumentsListed() { +String content = documentsListPage.getList().stream().map(x -> x.getText()).collect(Collectors.joining()); +Assert.assertTrue(content.contains("documentuser123")); +Assert.assertTrue(content.contains("DocumentITCase1")); +Assert.assertTrue(content.contains("DocumentITCase2")); +} + +@After +@Override +public void tearDown() { +super.tearDown(); +JDBC_HELPER.executeSqlScript( +"src/test/resources/sql/DocumentServiceITCase-deleteDocument.sql"); +} +} +\end{minted} \section{Toni FRAAGNAA} Den Code durchgehen - was statt null - welche Exception - logger ok? ob ein Throw im try Block ok ist. @@ -561,9 +725,12 @@ ob ein Throw im try Block ok ist. // dependency Injection // braucht man im Controller (ViewHelper) überhaupt noch Exception Handling + + //müssen wir die Folien genau beherrschen (Stubs vs. Mocks?) + + //Bei welchem Goal wird was mitausgeführt? IT-Test bei mvn wildfy:run? \end{minted} - \section{Frageart Prüfung} Welche Fehler können bei Exception-Handling vorkommen in unserem Projekt?? – wie funktioniert es grundsätzlich in unserem Code diff --git a/pse.pdf b/pse.pdf index aced8db..3d574f2 100644 Binary files a/pse.pdf and b/pse.pdf differ