Qualitätssicherung in ADF Projekten der IKB
Transcription
Qualitätssicherung in ADF Projekten der IKB
Qualitätssicherung in ADF Projekten der IKB Deutsche Industriebank AG Torsten Kleiber, DOAG Development, 4.6.2014 IKB – Bank des Mittelstands 2 IKB im Überblick Regionale Präsenz Seit 90 Jahren Finanzierungspartner des Mittelstands 2.500 Kunden in Deutschland und Europa1) Aktionäre: Lone Star 91,5 %, Streubesitz 8,5 % ca. 1.500 Mitarbeiter Bilanzsumme: € 25,8 Mrd.2) London Kernkapitalquote: 11,21 %2) Hamburg Berlin Düsseldorf (HQ) Frankfurt Leistungsspektrum Paris Kredit Capital Markets Advisory Bilaterale Finanzierung Debt Capital Markets M&A Fördermittel Equity Capital Markets Debt Advisory Konsortialfinanzierung Derivate Corporate Finance Leasing Sales & Trading Risikomanagement 1) Zzgl. 18.000 Kunden im Leasing-Geschäft 2) Stand: 30. September 2013 Stuttgart München Mailand Madrid Über mich 3 Torsten Kleiber Software Architekt, Entwickler Kreditplattform 15 Jahre IKB, 18 Jahre Oracle Erfahrung von Designer / Forms / Reports PL/SQL hin zu Architektur Fusion Middleware SOA Mediator ADF Development Tools Development Lifecycle Release Management Agenda 4 ADF in der IKB Warum und wie wird ADF in der IKB eingeführt? Zielstellung QS Welche Ziele werden bei den QS unterstützenden Prozessen und Tools verfolgt? Toolauswahl IDE / CI Warum wurden welche IDE und welcher CI Server ausgewählt? Statische Codeanalyse Welche Tools zur statischen Codeanalyse werden wie bei der IKB genutzt? Automatisierter Test Welche Tools für den automatischen Test werden wie bei der IKB genutzt? Code Abdeckung Wie ermittelt man, wieviel und welcher Code getestet ist? Evaluierung Welche Tools befinden sich noch in der Evaluierung? Fazit Der aktuelle Stand in den ADF Projekten. ADF in der IKB 5 Ausgangspunkt: Migration Eigenentwicklung zur Kredit und Darlehensverwaltung Forms & Reports ADF & ??? Entscheidung ADF hauptsächlich wegen Strategie bei Oracle Fusion Applications > 500 Forms, > 60 Menüs, > 40 Bibliotheken, > 350 Reports Ca. 50% der Module in englisch Startpunkt 2012 Migration 1 Eigenentwicklung MS Access ADF mit 6 Personen Gleichzeitig Einführung agiler Methoden (Kanban) Aktuell 16 Entwickler + 2 Tester + 3 Coaches (Opitz Consulting, esentri) Entwicklung neuer User Stories wenn möglich in ADF (SEPA, FATCA, …) Projekt zur Ablösung Forms & Reports über ca. 3 Jahre Aktuell ADF Version 11.1.1.5, Migration nach 12c ist für August 2014 geplant Internet Explorer als Browser gesetzt Zielstellung Qualitätssicherung 6 kontinuierliche qualitative Verbesserung der Code Basis – keine 100%! Erlernen von Best Practices Prüfen von Entscheidungen z.B. zu Architektur, Best Practices Konfiguration von gegebenen Regeln Erstellung von eigenen Regeln Dokumentation bewusster Abweichungen von Regeln im Code und Unterbindung der weiteren Verletzung Integration der Regeln in die IDE des Entwicklers Integration der Regeln in den Continuous Integration Prozess Konsequenzen im Delivery-Prozess bei Verletzung kritischer Regeln automatischer Regressionstest im Backend und der GUI Messung der Codeabdeckung durch Tests Toolauswahl – IDE und Continuous Integration Server 7 IDE - Standard ADF Stack (ADF BC, ADF Controller, ADF Faces) in der IKB, damit JDeveloper als IDE gesetzt. Continuous Integration Server - zunächst Oracle Hudson als CI Server eingeführt - Spezielle Anforderungen an Jobs durch Hudson nicht lösbar - Support bzw. ausreichende Weiterentwicklung konnte nicht beobachtet werden - Jenkins ist ein Fork von Hudson nach der Übernahme von Sun durch Oracle - Kostenlos, aber kostenpflichtiger Support möglich - Große Community - 600+ Plugins - Umstieg auf Jenkins nach Prüfung der Anforderungen in unter einem Tag Vorbereitungen 8 Zentrale versionierte Ablage aller Tools (außer Jenkins Plugins) wegen Upgrades Kann sowohl für JDeveloper als auch Jenkins verwendet werden Beispiel der Präsentations-Umgebung verfügbar auf: https://github.com/tkleiber/de.kleiber.ciroot.git Statische Codeanalyse - Tools 9 FindBugs Integrationen Checkstyle Bugs Potenzielle Probleme Bugs Nicht benötigten und suboptimalen Code Überkomplizierte Ausdrücke Duplizierten Code (CPD) Coding Standards Nur Java Code Schwer konfigurierbar Schwer erweiterbar Unterdrückung von Meldungen im Code möglich, aber komplex Bytecode erforderlich Schnell Java, JSP, JSF, XML, XSL … Einfach konfigurierbar Einfach erweiterbar (Java, XPath) Unterdrückung von Meldungen im Code möglich Nur Java Code Einfach konfigurierbar Einfach erweiterbar (Java) Unterdrückung von Meldungen im Code möglich Diverse IDE‘s Nicht JDeveloper ANT Maven Jenkins Hudson Diverse IDE‘s JDeveloper (rudimentär) ANT Maven Jenkins Hudson Diverse IDE‘s Nicht JDeveloper ANT Maven Jenkins Hudson Sucht / Prüft Vor- / Nachteile PMD Fazit: Die Tools decken verschieden Zwecke gut ab, sind im JDeveloper aber nur unzureichend integriert. Statische Codeanalyse – Anpassungen PMD 10 Aufgrund XML-Analyse und XPath-Regeln bot sich PMD für eigene Regeln an Anpassung für XML-Analyse von JDeveloper/ADF-Dateien in %pmd-src%\src\main\java\net\sourceforge\pmd\lang\Language.java XML("XML", null, "xml", XmlRuleChainVisitor.class, "xml"), XML("XML", null, "xml", XmlRuleChainVisitor.class, "xml", "jws", "jpr", "cpx", "xcfg", "dcx", "jpx"), PMD bauen (hier Windows) cd %pmd-src%\ set JDEV_HOME=C:\Oracle\JDev111240 set JAVA_HOME=%JDEV_HOME%\jdk160_24 %JDEV_HOME%\jdeveloper\apache-maven-2.2.1\bin\mvn clean package Datei in %ciroot%\root\lib\pmd\lib mit der aus %pmd-src%\target ersetzen Statische Codeanalyse – Regeln (1) 11 Standardregeln - Checkstyle: sun_checks.xml wird mit ausgeliefert - PMD: Verzeichnis rulesets in Source src\main\resources oder in pmd-x.x.x.jar Konfiguration, z.B. Checkstyle - Javadoc Tag Prüfung ist bei privaten Variablen nicht erforderlich, wenn dafür kein Javadoc erzeugt werden soll (und die Namen selbstdokumentierend sind) <module name="JavadocVariable"> <property name="excludeScope" value="private"/> </module> Statische Codeanalyse – Regeln (2) 12 Neue Regeln, PMD: Application Modules sollen auf JDBC Data Sources basieren <rule name="OracleAdfAmShouldNotBaseOnJdbcUrl" language="xml" message="ADF application module configurations should based on JDBC data sources, not on JDBC URLs" class="net.sourceforge.pmd.lang.rule.XPathRule"> <priority>1</priority> <properties> <property name="xpath"> <value> <![CDATA[ /BC4JConfig/AppModuleConfigBag/AppModuleConfig[@JDBCName] ]]> </value> </property> </properties> </rule> Statische Codeanalyse – Apache Ant 13 nur für PMD existiert für JDeveloper ein rudimentäres Plugin (gepflegt von mir) Checkstyle, PMD, FindBugs, JDeveloper in Version 11.1.1.5 und Jenkins unterstützen Ant Output in bestimmten Format ermöglicht Sprung zum Source Code im JDeveloper Checkstyle und PMD erfüllen Format, für FindBugs wurde ein Request angelegt Also: allgemeines Ant-Skripts mit folgenden Anforderungen - Welche Priorität der Regelverstöße soll angezeigt werden? - Wo liegen die zu analysierenden Source-Verzeichnisse oder –Dateien? - Wo ist das Middleware- und JDeveloper-Verzeichnis? - Relative Pfade für Wiederverwendbarkeit in JDeveloper und Jenkins - Einschränkung auf Java- und ADF-Dateien - Ausführung von FindBugs immer auf mindestens dem Projekt zur Datei wg. Vermeidung False Positives bezüglich Kopplungsregeln Statische Codeanalyse – JDeveloper External Tool 14 Tools External Tools New Type: Apache Ant Ant Buildfile: %ciroot%\root\check.xml Selected Targets: all (Default) Properties: - external.tool.sources.dir: ${file.dir} - external.tool.sources.file: ${file.name} - external.tool.sources.file.extension: ${file.ext} - external.tool.project.dirname: ${project.dirname} - external.tool.workspace.dir: ${workspace.dir} Caption for Menu Items / ToolTip Text: Checkstyle, FindBugs and PMD this Integration: Alle Checkboxes Statische Codeanalyse – Unterdrückung von Verletzungen 15 Ziele - Dokumentierte Unterdrückung im Einzelfall - Bestimmte Dateimuster (z.B. generierte Dateien) von der Analyse filtern Für die verschiedenen Tools gibt es verschiedene Arten der Unterdrückung, z.B.: - FindBugs: - Annotations (Hierzu muss FindBugs.jar in den Pfad genommen werden!): @edu.umd.cs.FindBugs.annotations.SuppressFBWarnings(value="<Regel>", justification="Begründung") - Konfiguration: Filter - PMD: - Annotations: @SuppressWarnings("PMD.<Regeltyp>") - Kommentare: // NOPMD (konfigurierbar) - Regelkonfiguration: Violation Suppress Regex / Xpath - Checkstyle - Kommentare: Checkstyle\:ON / Checkstyle\:OFF - Konfiguration: Filter (Regeln, Dateien, Zeilen) Statische Codeanalyse – Offene Punkte / Tasks 16 • Als Tasks werden bestimmte Tags bezeichnet, die der Kennzeichnung von unfertigem oder zu korrigierenden Code dienen • Workarounds für Fehler in Komponenten, von denen man abhängig ist, werden typischerweise so gekennzeichnet • Typische Tags sind • FIXME • TODO • TASK • Umfang des Codes mit solchen Tags sollte regelmäßig minimiert werden • Tasks werden in fast allen IDE‘s und CI Servern konfigurierbar unterstützt Statische Codeanalyse – Offene Punkte / Tasks im JDeveloper 17 11.x: View Tasks 12.x: Window Issues Live Issues Bugs: - nur *.java Dateien - Marker fehlt - Issues Scope falsch Statische Codeanalyse – Demo JDeveloper 18 Statische Codeanalyse im JDeveloper Beseitigen einer kritischen Verletzung Erneute Analyse, um Beseitigung der Verletzung nachzuweisen Unterdrückung einer Verletzung Erneute Analyse, um Unterdrückung der Verletzung nachzuweisen Anzeige eines Tasks Erledigen eines Tasks Commit Statische Codeanalyse – Jenkins Jobs & Plugins 19 CI Root: stellt aktuelles %ciroot% Verzeichnis für alle anderen Jobs bereit Summit – Build nach Commit: - Pollen VCS und Checkout bei Änderungen - Umgebung für Build konfigurieren (EnvInject Plugin) - Build der Deploymentprofile der Applications - Clone Jenkins Workspace für folgende Jobs (Clone Workspace SCM Plugin) Summit – Statische Codeanalyse: - Jenkins Workspace aus Build nach Commit (Clone Workspace SCM Plugin) - Umgebung für Codeanalyse konfigurieren (EnvInject Plugin) - Ausführen der Codeanalyse - Veröffentlichen Ergebnisse (FindBugs, PMD, Checkstyle, Task Scanner Plugin) - Zusammenfassung der Einzelergebnisse (Analysis Collector Plugin) Statische Codeanalyse – Abbruch bei hochpriorisierten Regelverstößen 20 Regelverstöße, die zu potenziellen Fehler führen, brechen auch den Job in Jenkins Beispiel: Application Modules sollen auf JDBC Datasourcen basieren (JDBC Url‘s verweisen immer auf dieselbe Datenbank, eine JDBC Datasource ist dagegen im Application Server für die entsprechende Umgebung konfiguriert) Separates Target im Ant-Skript <pmd rulesetfiles="pmd_config.xml" failonruleviolation="true"> … </pmd> Statische Codeanalyse – Demo Jenkins 21 Job - Trends Einzelergebnisse PMD -> PMD Warnungstypen Statische Analyse Ergebnis (Zusammenfassung) Job Instanz - Änderung Ergebnisse Statische Codeanalyse – Jenkins Trends 22 Statische Codeanalyse – Jenkins Einzelergebnisse Offene Punkte 23 Statische Codeanalyse – Jenkins Einzelergebnisse Checkstyle 24 Statische Codeanalyse – Jenkins Einzelergebnisse FindBugs 25 Statische Codeanalyse – Jenkins Einzelergebnisse PMD 26 Statische Codeanalyse – Jenkins Einzelergebnisse PMD Warnungstypen 27 Statische Codeanalyse – Statische Analyse Ergebnis (Zusammenfassung) 28 Statische Codeanalyse – Änderung Ergebnisse 29 Automatisierter Test - Tools 30 Mockito / Powermock JUnit Selenium Unterstützung der Isolation und Vortäuschung von Schnittstellen (Platzhalter) durch Inspektion der Klassen Unit Test in ADF BC Oberflächentest von WebAnwendungen Ziel Framework zum Schreiben reproduzierbarer Tests Direkter Test oder Ansteuerung anderer Frameworks Mockito: Vor-/Nachteile Assertions / Assumptions Fixtures Suite / Parameterized / Categories Runners Exception Testing Matchers Ignoring (nicht fertige Tests) Timeout für Tests Code (nicht als Anforderung lesbar) IDE für Aufzeichnung (Addon) WebDdriver (FF, IE, Chrome, Safari, Android, …) Server (lokal, remote) Grid (parallel mehrere Server) AJAX nicht einfach Nur Webanwendungen Diverse IDE‘s JDeveloperANT Maven Jenkins Hudson über JUnit alle auch dort genannten Integrationen Integration Einfaches Mocken Gute Lesbarkeit Finale Klassen / statische Methoden etc. nicht mockbar Powermock: Unterstützt Mockito-Style Konstruktoren / statische, private, finale Methoden über JUnit alle auch dort genannten Integrationen Fazit: Über die Kombination der Tools lassen sich Backend- und Oberflächentest für ADF abbilden. Automatisierter Test - Unit Test mit Mockito / Powermock 31 Mocking: Isolation von Tests durch Simulation des Verhalten verwendeter Objekte Weniger Aufwand/Fehler als bei selbstgeschriebenen Stubs Mockito - On the fly Erzeugung von Mock Objekten durch „Ausspähen“ - Nur erwartetes Verhalten wird überschrieben - Prüfung der korrekten Benutzung des verwendeten Objekts ist möglich - Plain Java Code (Code Completion) - Refactoring Safe - Type Safe - Wenig Code und gut lesbar Powermock - erweitert andere Mock-Frameworks PowerMockito für Mockito - Custom Classloader / ByteCode Manipulation für Mocking von statischen Methoden, Konstruktoren, finalen Klassen und Methoden, private Methoden etc. Automatisierter Test - Unit Test mit Mockito / Powermock: Beispiel Source 32 package oracle.summit.base; import oracle.jbo.server.DBTransaction; import oracle.jbo.server.EntityImpl; import oracle.jbo.server.SequenceImpl; public class SummitEntityImpl extends EntityImpl { public SummitEntityImpl() { super(); } public oracle.jbo.domain.Number nextValSequence(String sequenceName, DBTransaction db) { SequenceImpl s = getSequenceImpl(sequenceName, db); return s.getSequenceNumber(); } Refactoring für Injizierung Mock private SequenceImpl getSequenceImpl(String sequenceName, DBTransaction db) { return new SequenceImpl(sequenceName, db); } } Automatisierter Test - Unit Test mit Mockito / Powermock: Beispiel Test 33 @RunWith(PowerMockRunner.class) @PrepareForTest(SummitEntityImpl.class) public class SummitEntityImplTest { private SummitEntityImpl spy; private SequenceImpl sequenceImpl; private DBTransaction dBTransaction; private Number seqVal= new Number(1); Runner Class (PowerMock) ByteCode Transformation (PowerMock) @Before public void prepareTest() throws Exception { spy = PowerMockito.spy(new SummitEntityImpl()); Mockobjekte dBTransaction = Mockito.mock(DBTransaction.class); sequenceImpl = Mockito.mock(SequenceImpl.class); Mockito.when(sequenceImpl.getSequenceNumber()).thenReturn(seqVal); PowerMockito.doReturn(sequenceImpl).when(spy, "getSequenceImpl", "test", dBTransaction); } Test Erwartetes Testverhalten @Test public void testNextValSequence_test_db() throws Exception { assertEquals("Seq. not " + seqVal, seqVal, spy.nextValSequence("test", dBTransaction)); } } Automatisierter Test - GUI Test mit Selenium 34 Selenium IDE wird bei IKB nur selten zur Erstaufzeichnung von Tests genutzt Selenium Grid für parallelen Test auf verschiedener Hardware / Browsern / OS … Wrapper Bibliothek entwickelt für häufige Aufrufe, Testtreiber, Timeouts etc. Page Object Design Pattern (Trennen von Seiten und Testcode Refactoring besser möglich) AJAX? - Asynchrone Änderungen schwer trackbar - <af:statusIndicator/>: Abfrage des Attributes Name oder Alt des Icons Wegen Unverträglichkeit mit XML Parsern der ADF Editoren müssen Tests in separatem Projekt liegen (auch wg. Deployment als ADF Library sinnvoll) Derzeit Probleme mit Stabilität speziell des ersten Test nach Deployment Automatisierter Test - GUI Test mit Selenium – Page Object Index 35 public class Index { public static final String ENV_TEST_CONTEXT_ROOT = System.getenv("TEST_CONTEXT_ROOT"); public static final String TEST_CONTEXT_ROOT = (ENV_TEST_CONTEXT_ROOT != null ? ENV_TEST_CONTEXT_ROOT : "SummitADF-ViewController-context-root/faces/index"); private static final String ID_TAB_WELCOME = "pt1:sdi1::disAcr"; private static final String ID_TAB_INVENTORY_CONTROL = "pt1:sdi3::disAcr"; private static final String XPATH_BUSY_ICON = "//span[@id='pt1:statInd']/img"; private static final String VALUE_BUSY_ICON_ALT = "Frei"; protected UITestDriver driverInstance; public Index(final UITestDriver driverInstance) { this.driverInstance = driverInstance; } Reiterkarte „Welcome“ öffnen public void openTabWelcome() { driverInstance.clickById(ID_TAB_WELCOME); waitForAjaxCalls(); } public InventoryControl openTabInventoryControl() { driverInstance.clickById(ID_TAB_INVENTORY_CONTROL); waitForAjaxCalls(); return new InventoryControl(driverInstance); } public void waitForAjaxCalls() { driverInstance.waitForAlt(By.xpath(XPATH_BUSY_ICON), VALUE_BUSY_ICON_ALT); } Reiterkarte „Inventory Control“ öffnen Warten auf Abschluss von AJAX-Calls } Automatisierter Test - GUI Test mit Selenium – Page Object InventoryControl 36 public class InventoryControl extends Index { Ableitung der Masterseite private static final String XPATH_INVENTORY_CONTROL_HEADER = "//td[@id='pt1:r2:0:ph1::_afrTtxt']/div/h1"; XPath des Headers public InventoryControl(final UITestDriver driverInstance) { super(driverInstance); } Ermitteln des Headertexts public String getInventoryControlHeaderText() { return driverInstance.getTextByXpath( XPATH_INVENTORY_CONTROL_HEADER); } } Automatisierter Test - GUI Test mit Selenium – Test 37 public class IndexTest extends SeleniumTest { @Test public void testOpenTabWelcome() { driverInstance.getRelativeUrl(Index.TEST_CONTEXT_ROOT); final Index index = new Index(driverInstance); final InventoryControl inventoryControl= index.openTabInventoryControl(); assertEquals("Header is not correct", inventoryControl.getInventoryControlHeaderText(), "Inventory Items (Low Stock)"); } } Abstrakte Beschreibung des Tests Automatisierter Test - JUnit im JDeveloper 38 JUnit selbst für Tests oder als Wrapper für Mockito / PowerMockito / Selenium JUnit muss als Extension in den JDeveloper installiert werden Testausführung direkt im JDeveloper (außer PowerMockito in 12c – in Prüfung) Automatisierter Test - JUnit in Jenkins (1) 39 Derzeit wird das JUnit Target in ANT verwendet, um die Tests auszuführen <junit printsummary="yes" <classpath refid="classpath.test"/> <formatter type="xml"/> <batchtest fork="yes" todir="${basedir}/results/junit"> <fileset dir="${test.dir}"> <include name="${sub.junit.run.test.inlude}"/> </fileset> </batchtest> </junit> In Jenkins ist JUnit Reporting integriert, es muss nur ein Pattern zu den Ergebnissen angegeben werden Automatisierter Test - JUnit in Jenkins (2) 40 Trend Testergebnisse Testabdeckung - Jacoco 41 Ermittelt, wie der Sourcecode im Test abgedeckt wird Messung erfolgt derzeit nur für Unit-Tests on-the-fly instrumentation nicht nutzbar, da auch PowerMockito dynamic classfile transformation vornimmt und diese Testabdeckung dann nicht gemessen werden kann offline intrumentation <jacoco:instrument destdir="${jacoco.instrumented.classes.dir}"> <fileset dir="${base.project.classes.dir}"/> </jacoco:instrument> Ausführung ist Bestandteil der Testjobs und wrapped Junit (ANT) <jacoco:coverage destfile="${jacoco.exec.file}"> <junit printsummary="yes" fork="true" forkmode="once"> … </junit> </jacoco:coverage> Testabdeckung – Jacoco im JDeveloper 42 für den Entwickler wird per ANT ein Report erzeugt <jacoco:report> <executiondata><file file="${jacoco.exec.file}"/></executiondata> <structure name="${base.project.dir}"> <classfiles><fileset dir="${jacoco.instrumented.classes.dir}"/></classfiles> <sourcefiles><fileset dir="${base.project.sources.dir}"/></sourcefiles> </structure> <html destdir="${jacoco.results.dir}"/> </jacoco:report> Testabdeckung – Jacoco in Jenkins (1) 43 Im Jenkins kommt das JaCoCo Plugin zum Einsatz, Konfiguration: Reports Testabdeckung – Jacoco in Jenkins (2) 44 Reports (2) Evaluierung 45 ADF EMG Audit Rules (Implementierung der ADF Code Guidelines) - für 11.1.1.x seit kurzem verfügbar - in 11.1.1.x keine Meldungsunterdrückung möglich via Suppress Warnings Extension - 12c Sonarcube - ADF EMG Audit Rules für Prüfung in JDeveloper - SonarQube ojaudit plugin für Prüfung in Sonarcube via Jenkins - 12c Testparallelisierung (ab JUnit 4.8, JUnit 4.10 erst im Plugin für 12c enthalten) ADF Task Flow Tester Testabdeckung GUI-Tests … Fazit 46 Erreichte Ziele - Es wurden diverse Voraussetzungen für die automatisierte QS geschaffen - Zusätzlich zum automatisierten Test erfolgt ein Pre-Test in IT und der Acceptance Test in der Fachabteilung - Erste automatisierte Tests wurden erstellt - Know How in diversen Tools wurde aufgebaut Herausforderungen: - Schulung der Entwickler auf allen Gebieten - Aufwände in die agile Entwicklungsweise verankern für - Design und Automatisierung von Tests - Umsetzung der Ergebnisse der statischen Codeanalyse - Feinjustierung der Regeln Fragen & Antworten 47 Referenzen 48 Markus Sprunck: Direct Comparison of FindBugs, PMD and Checkstyle