18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.remarkrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "remark-preset-lint-recommended",
4 | ["remark-lint-list-item-indent", false]
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes of this coding style will be automatically
4 | logged by release drafter in [GitHub releases](https://github.com/uhafner/codingstyle/releases).
5 |
6 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | node('java-agent') {
2 | stage ('Checkout') {
3 | checkout scm
4 | }
5 |
6 | stage ('Git mining') {
7 | discoverGitReferenceBuild()
8 | mineRepository()
9 | gitDiffStat()
10 | }
11 |
12 | stage ('Build, Test, and Static Analysis') {
13 | withMaven(mavenLocalRepo: '/var/data/m2repository', mavenOpts: '-Xmx768m -Xms512m') {
14 | sh 'mvn -V -e clean verify -Dgpg.skip -Pci'
15 | }
16 |
17 | recordIssues tools: [java(), javaDoc()], aggregatingResults: 'true', id: 'java', name: 'Java'
18 | recordIssues tool: errorProne(), healthy: 1, unhealthy: 20
19 |
20 | junit testResults: '**/target/*-reports/TEST-*.xml'
21 |
22 | recordCoverage(tools: [[parser: 'JACOCO']],
23 | id: 'jacoco', name: 'JaCoCo Coverage',
24 | sourceCodeRetention: 'EVERY_BUILD',
25 | qualityGates: [
26 | [threshold: 60.0, metric: 'LINE', baseline: 'PROJECT', unstable: true],
27 | [threshold: 60.0, metric: 'BRANCH', baseline: 'PROJECT', unstable: true]])
28 |
29 | recordIssues tools: [checkStyle(pattern: 'target/checkstyle-result.xml'),
30 | spotBugs(pattern: 'target/spotbugsXml.xml'),
31 | pmdParser(pattern: 'target/pmd.xml'),
32 | cpd(pattern: 'target/cpd.xml'),
33 | taskScanner(highTags:'FIXME', normalTags:'TODO', includePattern: '**/*.java', excludePattern: 'target/**/*')],
34 | qualityGates: [[threshold: 1, type: 'TOTAL', unstable: true]]
35 | }
36 |
37 | stage ('Mutation Coverage') {
38 | withMaven(mavenLocalRepo: '/var/data/m2repository', mavenOpts: '-Xmx768m -Xms512m') {
39 | sh "mvn org.pitest:pitest-maven:mutationCoverage"
40 | }
41 | recordCoverage(tools: [[parser: 'PIT']],
42 | id: 'pit', name: 'Mutation Coverage',
43 | sourceCodeRetention: 'EVERY_BUILD',
44 | qualityGates: [
45 | [threshold: 60.0, metric: 'MUTATION', baseline: 'PROJECT', unstable: true]])
46 | }
47 |
48 | stage ('Collect Maven Warnings') {
49 | recordIssues tool: mavenConsole()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ---------------- Documents --------------
2 |
3 | http://creativecommons.org/licenses/by/4.0/
4 |
5 | ---------------- Sourcecode --------------
6 |
7 | MIT License
8 |
9 | Copyright (c) 2014-2023 Dr. Ullrich Hafner
10 |
11 | Permission is hereby granted, free of charge, to any person
12 | obtaining a copy of this software and associated documentation
13 | files (the "Software"), to deal in the Software without
14 | restriction, including without limitation the rights to use,
15 | copy, modify, merge, publish, distribute, sublicense, and/or sell
16 | copies of the Software, and to permit persons to whom the
17 | Software is furnished to do so, subject to the following
18 | conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 | OTHER DEALINGS IN THE SOFTWARE.
31 |
--------------------------------------------------------------------------------
/LIESMICH.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/uhafner/codingstyle/actions)
2 | [](https://github.com/uhafner/codingstyle/actions/workflows/codeql.yml)
3 | [](https://app.codecov.io/gh/uhafner/codingstyle)
4 | [](https://app.codecov.io/gh/uhafner/codingstyle)
5 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
6 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
7 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
8 |
9 | In jedem Java Projekt sollte der gesamte Quelltext die gleichen Kriterien bei Stil, Formatierung, etc.
10 | verwenden. In diesem Projekt werden die Kodierungsrichtlinien zu meinen Vorlesungen an der Hochschule
11 | München zusammengefasst.
12 |
13 | Dieses Projekt enthält neben der Dokumentation der wichtigsten Kodierungsrichtlinien auch gleichzeitig eine sinnvolle
14 | Konfiguration aller für Java kostenlos verfügbaren statischen Codeanalyse Tools mittels Maven. Diese dort enthaltenen und automatisch
15 | prüfbaren Richtlinien werden - soweit wie möglich - nicht mehr extra im Text erwähnt. Damit kann diese Projekt gleichzeitig als
16 | Vorlage für neue Projekte genutzt werden. Unterstützt werden aktuell folgende Tools:
17 | - [Checkstyle](https://checkstyle.org)
18 | - [PMD](https://pmd.github.io/)
19 | - [SpotBugs](https://spotbugs.github.io)
20 | - [Error Prone](https://errorprone.info)
21 |
22 | Die automatisch prüfbaren Richtlinien können für CheckStyle und Error Prone auch direkt als Warnungen in der
23 | Entwicklungsumgebung [IntelliJ](https://www.jetbrains.com/idea/) angezeigt werden (nach der Installation des
24 | entsprechenden IntelliJ Plugins). Zusätzlich sind die
25 | [IntelliJ Code Inspections](https://www.jetbrains.com/help/idea/code-inspection.html) gemäß meiner Richtlinien konfiguriert.
26 | Aktuell können diese allerdings noch nicht automatisch im Build überprüft werden
27 | (siehe [#7](https://github.com/uhafner/codingstyle/issues/7)). Insgesamt ist damit sichergestellt,
28 | dass immer die gleichen Warnungen angezeigt werden - egal wie und wo die Java Dateien weiterverarbeitet werden.
29 | Für SpotBugs und PMD ist der Umweg über das Build Management Tool [Maven](http://maven.apache.org/) erforderlich
30 | (die entsprechenden IntelliJ Plugins sind leider aus meiner Sicht noch nicht ausgereift genug bzw. verwenden eine separate Konfiguration).
31 | Die Verwendung von Maven hat zudem den Vorteil, dass die Ergebnisse hinterher leicht in den Continuous Integration Server
32 | [Jenkins](https://jenkins.io/) eingebunden werden können. Eine beispielhafte Integration in GitHub Actions und Jenkins ist auch bereits vorhanden.
33 | Diese ist im eigenen Abschnitt [Continuous Integration](doc/Continuous-Integration.md)
34 | ausführlicher beschrieben. Ebenso sind mehrere externe Tools konfiguriert, die die Qualität der Pull Requests
35 | in diesem Repository bewerten, Details dazu sind im Abschnitt [Integration externer Tools](doc/Externe-Tool-Integration.md)
36 | beschrieben.
37 |
38 | Die Richtlinien sind in den Vorlesungen 2014/2015 entstanden und werden laufend ergänzt.
39 | Aktuell bestehen diese aus den folgenden Abschnitten:
40 |
41 | - [Formatierung](doc/Formatierung.md)
42 | - [Namensgebung](doc/Namensgebung.md)
43 | - [Kommentare](doc/Kommentare.md)
44 | - Testen
45 | - [Allgemeine Tipps zum Testen](doc/Testen.md)
46 | - [State Based vs. Interaction Based Testing](doc/State-Based-Vs-Interaction-Based.md)
47 | - [Testen von Schnittstellen und Basisklassen](doc/Abstract-Test-Pattern.md)
48 | - [Fehlerbehandlung](doc/Fehlerbehandlung.md)
49 | - [Best Practice](doc/Best-Practice.md)
50 |
51 | Zur besseren Verdeutlichung der angesprochenen Themen sind diesem Projekt auch [Java Beispiele](./src/) angefügt,
52 | die sich möglichst genau an diese Richtlinien halten.
53 |
54 | Ideen und Inhalte für diesen Styleguide lieferten verschiedene Bücher, insbesondere aber das Buch
55 | "The Elements of Java Style" [1]. Diese Bücher sind allesamt wegweisend für die Softwareentwicklung und sind
56 | damit Pflichtlektüre für Berufstätige in der Softwareentwicklung:
57 | - [1] "The Elements of Java Style", Vermeulen, Ambler, Bumgardner, Metz, Misfeldt, Shur und Thompson, Cambridge University Press, 2000
58 | - [2] "The Pragmatic Programmer. From Journeyman to Master", Andrew Hunt, David Thomas, Ward Cunningham, Addison Wesley, 1999
59 | - [3] "Code Complete: A Practical Handbook of Software Construction", Steve McConnell, Microsoft Press, 2004
60 | - [4] "Clean Code: A Handbook of Agile Software Craftsmanship", Robert C. Martin, Prentice Hall, 2008
61 | - [5] "Effective Java", Third Edition, Joshua Bloch, Addison Wesley, 2017
62 | - [6] "Refactoring: Improving the Design of Existing Code", Martin Fowler, Addison Wesley, 1999
63 | - [7] "Java by Comparison", Simon Harrer, Jörg Lenhard, Linus Dietz, Pragmatic Programmers, 2018
64 |
65 | Die gesamten Dokumente dieser Kodierungsrichtlinien unterliegen der
66 | [Creative Commons Attribution 4.0 International Lizenz](https://creativecommons.org/licenses/by/4.0/). Der
67 | Quelltext aller Beispiele und Klassen unterliegt der [MIT Lizenz](https://en.wikipedia.org/wiki/MIT_License).
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/uhafner/codingstyle/actions)
2 | [](https://github.com/uhafner/codingstyle/actions/workflows/codeql.yml)
3 | [](https://app.codecov.io/gh/uhafner/codingstyle)
4 | [](https://app.codecov.io/gh/uhafner/codingstyle)
5 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
6 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
7 | [](https://github.com/uhafner/codingstyle/actions/workflows/quality-monitor-pit.yml)
8 |
9 | Each Java project should follow a given coding style.
10 | I.e., all contributions to the source code should use the same formatting rules, design principles, code patterns, idioms, etc.
11 | This coding style provides the set of rules that I am using in my lectures about software development at Munich University of Applied Sciences.
12 |
13 | This project describes the coding style in detail (currently only available in German) and serves as a template project.
14 | It provides all necessary resources for a Java project to enforce this coding style using the following static analysis tools via Maven (and partly in IntelliJ):
15 | - [Checkstyle](https://checkstyle.org)
16 | - [PMD](https://pmd.github.io/)
17 | - [SpotBugs](https://spotbugs.github.io)
18 | - [Error Prone](https://errorprone.info)
19 |
20 | ❗This project requires a JDK version of 17 or higher.❗
21 |
22 | Moreover, this project provides some sample classes that already use this style guide.
23 | These classes can be used as such but are not required in this project.
24 | These classes also use some additional libraries that are included using the Maven dependency mechanism.
25 | If the sample classes are deleted, then the dependencies can be safely deleted, too.
26 |
27 | This project and the associated static analysis tools are already running in continuous integration: an example CI pipeline is active for GitHub Actions.
28 | For [Jenkins](https://jenkins.io/) a full CI pipeline has been configured that includes stages to compile, test, run static code analysis, run code coverage analysis, and run mutation coverage analysis, see section [Continuous Integration](doc/Continuous-Integration.md) for details.
29 | Additionally, some development tools are configured in this GitHub project to evaluate the quality of pull requests, see section [integration of external tools](doc/Externe-Tool-Integration.md).
30 |
31 | Content of the style guide (only in German):
32 | - [Formatierung](doc/Formatierung.md)
33 | - [Namensgebung](doc/Namensgebung.md)
34 | - [Kommentare](doc/Kommentare.md)
35 | - Testen
36 | - [Allgemeine Tipps zum Testen](doc/Testen.md)
37 | - [State Based vs. Interaction Based Testing](doc/State-Based-Vs-Interaction-Based.md)
38 | - [Testen von Schnittstellen und Basisklassen](doc/Abstract-Test-Pattern.md)
39 | - [Fehlerbehandlung](doc/Fehlerbehandlung.md)
40 | - [Best Practice](doc/Best-Practice.md)
41 |
42 | A lot of ideas in this style are based on the following path-breaking books about software development:
43 |
44 | - [1] "The Elements of Java Style", Vermeulen, Ambler, Bumgardner, Metz, Misfeldt, Shur und Thompson, Cambridge University Press, 2000
45 | - [2] "The Pragmatic Programmer: journey to mastery", Second Edition, Andrew Hunt, David Thomas, Addison Wesley, 2019
46 | - [3] "Code Complete: A Practical Handbook of Software Construction", Steve McConnell, Microsoft Press, 2004
47 | - [4] "Clean Code: A Handbook of Agile Software Craftsmanship", Robert C. Martin, Prentice Hall, 2008
48 | - [5] "Effective Java", Third Edition, Joshua Bloch, Addison Wesley, 2017
49 | - [6] "Refactoring: Improving the Design of Existing Code", Martin Fowler, Addison Wesley, 1999
50 | - [7] "Java by Comparison", Simon Harrer, Jörg Lenhard, Linus Dietz, Pragmatic Programmers, 2018
51 |
52 | All documents in this project use the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/).
53 | Source code (snippets, examples, and classes) are using the [MIT license](https://en.wikipedia.org/wiki/MIT_License).
54 |
55 | [](https://en.wikipedia.org/wiki/MIT_License)
56 | [](https://creativecommons.org/licenses/by/4.0/)
57 | 
58 |
--------------------------------------------------------------------------------
/badges/branch-coverage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/bugs.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/line-coverage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/mutation-coverage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/badges/style.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/bin/jenkins.sh:
--------------------------------------------------------------------------------
1 | # Make sure that docker runs with the current UID to avoid permission problems on volume docker/volumes/jenkins-home
2 | CURRENT_UID="$(id -u)"
3 | export CURRENT_UID
4 |
5 | CURRENT_GID="$(id -g)"
6 | export CURRENT_GID
7 |
8 | CURRENT_USER="$(id -u):$(id -g)"
9 | export CURRENT_USER
10 |
11 | echo Running docker compose with user ID $CURRENT_USER
12 |
13 | docker pull jenkins/jenkins:lts-jdk21
14 | docker compose build --pull
15 | docker compose up --always-recreate-deps
16 |
--------------------------------------------------------------------------------
/bin/release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | git pull
4 | git push
5 | mvn -B clean build-helper:parse-version release:prepare release:perform -DdevelopmentVersion=\${parsedVersion.majorVersion}.\${parsedVersion.nextMinorVersion}.0-SNAPSHOT
6 | mvn -Dproject.version=\${parsedVersion.majorVersion}.\${parsedVersion.minorVersion}.\${parsedVersion.patchVersion} com.github.ferstl:depgraph-maven-plugin:graph scm:add -Dincludes=doc/dependency-graph.puml
7 |
--------------------------------------------------------------------------------
/bin/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | git pull
4 | git push
5 | mvn build-helper:parse-version
6 | mvn -Dproject.version=1.0.0 com.github.ferstl:depgraph-maven-plugin:graph
7 |
--------------------------------------------------------------------------------
/doc/Continuous-Integration.md:
--------------------------------------------------------------------------------
1 | # Continuous Integration des Coding Style
2 |
3 | Gemäß dem Grundsatz **eat your own dogfood** ist dieser Coding Style bereits für die Continuous Integration in [GitHub Actions](https://github.com/features/actions), [GitLab CI](https://docs.gitlab.com/ee/ci/) und [Jenkins](https://jenkins.io) vorbereitet.
4 |
5 | ## Maven Konfiguration
6 |
7 | Sowohl für GitHub Actions als auch für Jenkins erfolgt die Automatisierung des Builds über Maven. Im zugehörigen [POM](../pom.xml) sind alle Versionen der benutzten Maven Plugins und der benötigten Abhängigkeiten über Properties definiert, d.h. eine Aktualisierung lässt sich im entsprechenden Abschnitt leicht selbst durchführen bzw. wird über den [Dependabot](https://dependabot.com) Roboter von GitHub automatisch über einen Pull Request aktualisiert.
8 | U.a. sind die folgenden Plugins vorkonfiguriert:
9 | - maven-compiler-plugin: konfiguriert die Java Version auf Java 11 und legt alle Error Prone Regeln fest. Die Java Version kann beliebig aktualisiert werden.
10 | - maven-javadoc-plugin: aktiviert die strikte Prüfung von JavaDoc Kommentaren
11 | - maven-jar-plugin: legt einen Modulnamen fest. Außerdem wird ein test-jar konfiguriert, sodass alle Tests (und abstrakte Testklassen) auch als Dependencies genutzt werden können.
12 | - maven-pmd-plugin: prüft das Projekt mit [PMD](https://pmd.github.io/), die Regeln liegen in den Dateien [pmd-java-configuration.xml](../etc/pmd-java-configuration.xml), [pmd-tests-configuration.xml](../etc/pmd-tests-configuration.xml) und [pmd-javascript-configuration.xml](../etc/pmd-javascript-configuration.xml).
13 | - maven-checkstyle-plugin: prüft das Projekt mit [CheckStyle](https://checkstyle.sourceforge.io/), die Regeln liegen in den Dateien [checkstyle-java-configuration.xml](../etc/checkstyle-java-configuration.xml) und [checkstyle-tests-configuration.xml](../etc/checkstyle-tests-configuration.xml).
14 | - spotbugs-maven-plugin: prüft das Projekt mit [SpotBugs](https://spotbugs.github.io/), alle Regeln werden verwendet mit den Ausnahmen definiert in der Datei [spotbugs-exclusion-filter.xml](../etc/spotbugs-exclusion-filter.xml).
15 | - revapi-maven-plugin: prüft, ob die aktuelle Versionsnummer die [semantische Versionierung](https://semver.org) berücksichtigt (source and binary). D.h. es gilt:
16 | 1. Eine neue **Major** Version wurde definiert, wenn das API nicht mehr abwärtskompatibel ist.
17 | 2. Eine neue **Minor** Version wurde definiert, wenn eine neue Funktionalität abwärtskompatibel hinzugefügt wurde.
18 | 3. Eine neue **Patch** Version wurde definiert, wenn Fehler abwärtskompatibel behoben wurden.
19 | - maven-surefire-plugin: aktiviert das Erkennen der Annotationen der Architekturtests mit [ArchUnit](https://www.archunit.org)
20 | - jacoco-maven-plugin: misst die Code Coverage der Testfälle mit [JaCoCo](https://www.jacoco.org)
21 | - pitest-maven: misst die Mutation Coverage der Testfälle mit [PITest](http://pitest.org)
22 |
23 | ## GitHub Actions
24 |
25 | [](https://github.com/uhafner/codingstyle/actions)
26 |
27 | Die Konfiguration der Continuous Integration in GitHub Actions is sehr [einfach](../.github/workflows/ci.yml) über eine Pipeline möglich. Da der gesamte Build über Maven automatisiert ist, besteht die Pipeline eigentlich nur aus einem Maven Aufruf, der das Projekt baut, alle Tests (Unit und Integrationstests) ausgeführt, die statische Code Analyse durchführt und schließlich die Coverage misst. GitHub Actions bietet auch die Möglichkeit, Matrix Builds durchzuführen: d.h., der Build wird z.B. auf den Plattformen Linux, Windows und macOS oder mit den Java Versionen 17 und 21 parallel durchgeführt. Ein Beispiel für die Konfiguration eines Matrix Builds ist in der Datei [ci.yml](../.github/workflows/ci.yml) zu finden.
28 |
29 | Wenn gewünscht, können die Ergebnisse der statischen Code Analyse und der Code Coverage Tools auch direkt im Commit oder Pull-Request angezeigt werden. Dazu muss in der Pipeline meine [Quality Monitor Action](https://github.com/uhafner/quality-monitor) aktiviert werden. Eine Beispielkonfiguration ist in der Datei [quality-monitor-pit.yml](../.github/workflows/quality-monitor-pit.yml) zu finden, das Ergebnis in der nachfolgenden Abbildung:
30 |
31 | 
32 |
33 | ## Jenkins
34 |
35 | Eine Beispielintegration mit Jenkins ist auch bereits vorhanden. Diese ist im [Jenkinsfile](../Jenkinsfile) hinterlegt und startet die Integration in mehreren Schritten (Stages). Zunächst werden auch hier alle Schritte wie in GitHub Actions aufgerufen. Anschließend erfolgt noch ein Start der Mutation Coverage mit [PIT](http://pitest.org). Insgesamt ist die CI Konfiguration für Jenkins umfangreicher, da nicht nur der eigentliche Build konfiguriert wird, sondern auch die Darstellung der Ergebnisse im Jenkins UI über die entsprechenden Jenkins Plugins konfiguriert wird.
36 |
37 | ### Lokale CI in Jenkins (über Docker Compose)
38 |
39 | Da es für Jenkins keinen öffentlichen Service wie bei GitHub Actions gibt, um eigene Projekte zu bauen, muss die Jenkins Integration lokal auf einem Team-Server durchgeführt werden. Zur Vereinfachung des Jenkins Setup ist in diesem Coding Style eine lauffähige Jenkins Installation enthalten (im Sinne von *Infrastructure as Code*). Diese kann über `bin/jenkins.sh` gestartet werden. Anschließend wird die aktuelle Jenkins LTS Version mit allen benötigten Plugins in einem Docker Container gebaut und gestartet (das dauert beim ersten Aufruf etwas). Dazu wird ebenso ein als Docker Container initialisierter Java Agent verbunden, der die Builds ausführt.
40 |
41 |
42 | Nach einem erfolgreichen Start von Jenkins sind dann unter [http://localhost:8080](http://localhost:8080) mehrere Jenkins Jobs sichtbar. Einer dieser Jobs baut das vorliegende Coding Style Projekt. Der Zugang auf diesen lokalen Rechner erfolgt zur Vereinfachung mit Benutzer `admin` und Passwort `admin`, anschließend hat man volle Jenkins Administrationsrechte. Die jeweiligen Jobs müssen danach manuell gestartet werden, die Ergebnisse der Tests, Code und Mutation Coverage sowie statischen Analyse werden dann automatisch visualisiert. Das Jenkins Home Verzeichnis ist im Docker Container als externes Volume angelegt: d.h. der Zugriff kann auf dem Host direkt im Verzeichnis `docker/volumes/jenkins-home` erfolgen.
43 |
44 | Nach einem ersten Build in Jenkins sollte sich dann in etwa folgendes Bild ergeben:
45 |
46 | 
47 |
--------------------------------------------------------------------------------
/doc/Externe-Tool-Integration.md:
--------------------------------------------------------------------------------
1 | # Integration externer Tools
2 |
3 | Zur Unterstützung des Entwicklungsworkflows sind bereits verschiedene externe Tools konfiguriert.
4 |
5 | ## Automatische Aktualisierung der Abhängigkeiten
6 |
7 | Die Abhängigkeiten des Projektes (Dependencies) werden über Maven verwaltet und sind im [POM](../pom.xml) konfiguriert.
8 | Um das Projekt immer auf dem laufenden Stand zu halten, ist die GitHub App [Dependabot](https://dependabot.com)
9 | aktiv geschaltet: diese prüft automatisch, on neue Versionen einer Bibliothek (oder eines Maven Plugins) zur Verfügung
10 | stehen. Ist dies der Fall, erstellt der Roboter automatisch einen
11 | [Pull Request](https://github.com/uhafner/codingstyle/pulls), der die Version aktualisiert.
12 |
13 | ## Automatisierte Generierung eines Changelog
14 |
15 | Damit der Nutzer des Projekts immer über alle Änderungen im Projekt im Bilde ist, ist die GitHub App
16 | [Release Drafter](https://github.com/toolmantim/release-drafter) aktiviert. Diese erstellt automatisch neue Changelog
17 | Einträge im [GitHub Releases Bereich](https://github.com/uhafner/codingstyle/releases). Diese Einträge werden
18 | aus den Titeln der Pull Requests generiert, d.h. jede Änderung am Projekt sollte über Pull Requests erfolgen und nicht
19 | über direkte Git Commits - dies entspricht auch dem Vorgehen des [GitHub Flows](https://guides.github.com/introduction/flow/).
20 |
21 | ## Statische Analyse von Pull Requests mit CheckStyle und PMD
22 |
23 | Wie bereits im Abschnitt [Continuous Integration](Continuous-Integration.md) erwähnt, gibt es keinen öffentlichen
24 | Service, ein GitHub Projekt mit Jenkins automatisiert zu bauen. Für GitHub Actions gibt es diesen Service, aber
25 | die Visualisierung der Ergebnisse der statischen Analyse wird leider nicht unterstützt.
26 |
27 | ## Security Analyse von Pull Requests
28 |
29 | Zusätzlich zur statischen Analyse wird ein Pull Request auf Sicherheitslücken untersucht. Dies erfolgt über die GitHub
30 | App [LGTM](https://lgtm.com).
31 |
32 | ## Bewertung der Code Coverage
33 |
34 | Die Code Coverage der Unit-Tests wird ebenfalls nach jeder Änderung (bzw. für jeden Pull Request) an den Service
35 | [Codecov](https://app.codecov.io/gh/uhafner/codingstyle) weitergeleitet, der die Resultate grafisch visualisiert.
36 |
--------------------------------------------------------------------------------
/doc/Fehlerbehandlung.md:
--------------------------------------------------------------------------------
1 | # Fehlerbehandlung mit Exceptions
2 |
3 | In einem Java-Programm können zur Laufzeit verschiedene Fehler auftreten:
4 | - logische Fehler (z.B. Programmierfehler)
5 | - Problem im Java-Laufzeitsystem (z.B. Speichermangel)
6 | - Probleme mit der Peripherie (z.B. mit Internet, Datenbank, Dateisystem)
7 | - fehlerhafte Bedienung (z.B. Benutzereingaben)
8 |
9 | Zum Melden eines solchen Fehlers benutzen wir i.A. Exceptions. D.h. bei Auftritt eines dieser Fehler wird das
10 | Programm an der aktuellen Stelle abgebrochen und eine Exception wird geworfen. Dies hat den Vorteil, dass diese
11 | Laufzeitfehler behandelt werden müssen, und somit nicht ignoriert werden können.
12 |
13 | Auf diese Fehler kann anschließend an geeigneter Stelle im Programm reagiert werden. Je nach Fehler kann
14 | - die zum Fehler führende Handlung wiederholt werden (Internet ist wieder verfügbar, Benutzereingabe verbessert)
15 | - der Fehler in einem Dialog angezeigt werden
16 | - der Fehler ignoriert werden
17 | - das Programm abgebrochen werden
18 |
19 | Wird keine Fehlerbehandlung umgesetzt, wird das Programm mit einem Stacktrace beendet.
20 |
21 | ## Validieren von Eingabeparametern
22 |
23 | Sichere und robuste Software vertraut niemals Eingabewerten. Es gilt der Grundsatz: „all input is evil“. D.h. in
24 | öffentlichen Methoden und Konstruktoren müssen Parameter immer validiert werden.
25 | Genügen diese Parameter nicht dem erwarteten Vertrag, muss eine Exception geworfen werfen. I.A. ist dafür die
26 | `IllegalArgumentExeption` geeignet. Ggf. kann davon abgewichen werden, um z.B. mit der `IndexOutOfBoundsException` oder
27 | der `IllegalStateException` eine genauere Fehlerursache aufzuzeigen. Die `NullPointerException` hat einen Sonderstatus,
28 | sie wird i.A. automatisch geworfen bei Zugriff auf `null`. Ein Werfen dieser Exception ist nur nötig, falls ein
29 | Parameter ohne direkte Nutzung in einer Objektvariable gespeichert wird.
30 |
31 | ## Exception-Typen
32 |
33 | Im JDK ist eine Vielzahl von Exception Klassen vordefiniert, diese haben alle die Endung `Exception` im Klassennamen.
34 | Es macht selten Sinn, eigene weitere Exceptions zu definieren. Wird eine Exception benötigt, ist i.A. im JDK
35 | immer eine passende dabei.
36 |
37 | Java bietet als einzige Programmiersprache zwei verschiedene Exception Kategorien an:
38 | - checked Exceptions: müssen deklariert und gefangen werden
39 | - unchecked Exceptions: können deklariert und gefangen werden
40 |
41 | Das Konzept hat sich in der Praxis nicht bewährt (Details gibt es in Artikeln wie [Checked Exceptions are Evil](https://phauer.com/2015/checked-exceptions-are-evil/)
42 | oder [The Trouble with Checked Exceptions](https://www.artima.com/intv/handcuffs.html)),
43 | daher nutzen wir möglichst immer unchecked Exceptions. Werden Bibliotheken genutzt, die mit checked Exceptions arbeiten,
44 | bietet es sich an, diese an der Aufrufstelle zu fangen und in eine äquivalente unchecked Exception umzuwandeln.
45 |
46 | ## Dokumentation von Exceptions
47 |
48 | Wenn Methoden oder Konstruktoren eine Exception werfen können, sollte dies im Methodenkopf mit einer `throws` Klausel
49 | und im JavaDoc mit einem `@throws` Tag dokumentiert werden. Dort sollte auch immer der Grund beschrieben sein. Dies ist
50 | nicht kaskadierend erforderlich, d.h. eine Methode die mehrere Methoden aufruft, die Exceptions werfen muss diese nicht
51 | mehr aufführen, sondern nur die selbst geworfenen Exceptions.
52 |
53 | ## Fehlerursache (Kontext)
54 |
55 | Wird eine Exception geworfen, muss die Fehlerursache (d.h. der Kontext) genau lokalisiert werden, und als Text im
56 | Konstruktor der Exception übergeben werden. D.h. was ist das Problem? Wie konnte das Problem auftreten?
57 | Welche Parameterwerte sind Ursache? Diese Meldung ist i.A. nur sichtbar für das Entwicklungsteam und kann z.B. auch dafür
58 | passend formuliert werden. Wird darüber hinaus eine andere Exception gefangen und umgewandelt,
59 | so ist diese auch im Konstruktor der neuen Exception zu übergeben. Generell gilt: Der Default-Konstruktor einer
60 | Exception darf **nie** verwendet werden.
61 |
62 | ## Testen von Exceptions
63 |
64 | Das korrekte Werfen von Exceptions sollte generell getestet werden, siehe dazu den passenden Abschnitt im Kapitel zum
65 | [Testen](Testen.md#testen-von-exceptions).
66 |
67 | ## Best practice
68 |
69 | Exceptions dürfen nur für außergewöhnliche Ereignisse verwendet werden, d.h. die Programmflusssteuerung darf
70 | niemals über Exceptions durchgeführt werden. Dies lässt sich umso leichter erreichen, wenn es zu jeder Methode **x** eine
71 | zweite Methode **y** gibt, die prüft, ob die Methode **x** mit den gegebenen Eingabeparametern
72 | eine Exception werfen würde.
73 |
74 | Beispiele: Eine `IndexOutOfBoundsException` lässt sich bei `list.get(0)` vermeiden, wenn vorab die Anzahl der Elemente
75 | geprüft wird (mit `isEmpty()` oder `size()`). Analoge Methodenpaare finden sich z.B. bei `get(object)` und `contains(object)`,
76 | oder `new FileInputStream(file)` und `file.exists()`, oder `iterator.next()` und `iterator.hasNext()`.
77 |
78 | Exceptions können mit try/catch/finally Blöcken gefangen werden. Dadurch wird der Code recht schnell
79 | unübersichtlich, da das **Single Responsibility Principle** (siehe [4, S. 138-139]) verletzt wird.
80 | Sinnvoll ist daher das Aufteilen des Programmstücks in die folgenden Teile:
81 | - im try Block: Aufruf einer Untermethode (keine Fehlerbehandlung)
82 | - im catch Block: Fehlerbehandlung
83 | - im finally Block: ggf. Aufräumen
84 | - in der Untermethode: Implementierung der Anforderungen ohne Rücksicht auf Exceptions
85 |
86 | In einem finally Block sollte niemals eine Exception geworfen werden. Außerdem sollte im finally Block niemals die
87 | Methode mit return beendet werden.
88 |
89 | Ebenso sollten Exceptions niemals ignoriert werden. Sollte es erforderlich sein, einen leeren catch Block zu verwenden, so muss
90 | dies mit einem Kommentar versehen werden!
91 |
--------------------------------------------------------------------------------
/doc/Git.md:
--------------------------------------------------------------------------------
1 | Alle Dokumente und Sourcen, die im Semester erstellt werden,
2 | müssen in einer Versionsverwaltung abgelegt werden - dies bezieht sich
3 | auf Texte, UML Diagramme und Source Code. Wir benutzen dafür
4 | [Git](https://git-scm.com). Git ist eine verteilte Versionsverwaltung, d.h.
5 | das Repository, das alle Änderungen an unseren Dateien abspeichert, ist
6 | auf mehreren Rechnern verteilt. Zum einen auf den eigenen lokalen Rechnern der
7 | Teammitglieder und zum anderen auf einem zentralen Server, der als
8 | Synchronisierungsknoten für das Team verwendet wird. Dieser Server wird
9 | typischerweise von einem sogenannten Hoster (oder Service Provider) zur Verfügung gestellt.
10 | Aktuell ist GitHub der bekannteste Hoster, aber auch GitLab oder BitBucket sind
11 | in der Industrie weit verbreitet. Die Hochschule bietet selbst auch ein Hosting über
12 | das LRZ an: hier kommt die Software von GitLab zum Einsatz, allerdings auf unserer eigenen
13 | Hardware.
14 |
15 | Die Arbeit mit Git ist schnell gelernt, es gibt dazu eine Vielzahl an Online verfügbaren
16 | Quellen, die im folgenden aufgelistet sind:
17 | - [Learn Version Control with Git](https://www.git-tower.com/learn/git/videos/) Video Tutorials vom
18 | Tower Team (inkl. passendem [Git Cheat Sheet](https://www.git-tower.com/blog/git-cheat-sheet/))
19 | - [Learn Git with GitKraken](https://www.gitkraken.com/resources/learn-git) Video Tutorials vom GitKraken Team
20 | - [Das Git-Buch](http://gitbu.ch/index.html) von Valentin Haenel und Julius Plenz
21 | - Das [Pro Git](https://git-scm.com/book/de/v2) Buch von Scott Chacon
22 | - [Git and GitHub learning resources](https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/git-and-github-learning-resources) vom GitHub Team
23 | (inkl. passendem [Git Cheat Sheet](https://education.github.com/git-cheat-sheet-education.pdf))
24 | - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/) von Chris Beams
25 |
26 |
27 |
--------------------------------------------------------------------------------
/doc/Kommentare.md:
--------------------------------------------------------------------------------
1 | # Kommentare
2 |
3 | Java kennt drei verschiedene Varianten von Kommentaren:
4 | - der einzeilige Kommentar wird mit `//` eingeleitet und geht bis zum Zeilenende
5 | - der mehrzeilige Kommentar wird mit `/*` gestartet und mit `*/` beendet
6 | - der JavaDoc Kommentar wird mit `/**` gestartet und mit `*/` beendet.
7 |
8 | ## Kommentare zum Quelltext
9 |
10 | Wohlüberlegte Kommentare *können* die Qualität des Quelltextes steigern. Sie sind i.A. ein notwendiges Übel und
11 | helfen uns darüber hinweg, dass wir nicht alles durch Code alleine ausdrücken können. Dafür kann eine der beiden
12 | ersten Varianten genutzt werden. Diese erklären das Ziel des Quelltextes und verdeutlichen damit unsere Absicht.
13 |
14 | Wichtig zu beachten sind aber die folgenden Aussagen von Brian W. Kernighan:
15 | - Make sure comments and code agree.
16 | - Don't just echo the code with comments - make every comment count.
17 | - Don't comment bad code - rewrite it.
18 |
19 | (Aus dem Klassiker: B. W. Kernighan and P. J. Plauger, The Elements of Programming Style, McGraw-Hill, New York, 1974)
20 |
21 | Insgesamt gilt: so wenig Kommentare wie nötig verwenden. Besser Bezeichner passend auswählen und komplexen Code vereinfachen oder
22 | z.B. durch zusätzliche Methoden strukturieren. D.h. bevor ein Kommentar für einen komplexen
23 | Programmausschnitt erstellt wird, sollte dieser Ausschnitt in eine Methode ausgelagert werden. Die Methode selbst wird dann
24 | mit dem beabsichtigten Kommentar benannt. Eine ausführlichere Behandlung dieses Themas findet sich in [4], dort
25 | sind viele Beispiele und Negativbeispiele aufgeführt.
26 |
27 |
28 | ## Spezielle Kommentare
29 |
30 | Häufig findet man auch Kommentare zur Kennzeichnung des Copyrights. Auch wenn diese den obigen Regeln widersprechen,
31 | müssen diese aus juristischen Gründen in vielen Dateien vorhanden sein.
32 |
33 | Werden in einem Programmabschnitt kleine Verbesserungsmöglichkeiten entdeckt, die im Moment nicht behoben werden können,
34 | so können diese ebenso mit einem Kommentar beschrieben werden. Hier ist wichtig, die Kommentare mit einer Markierung
35 | wie TODO oder FIXME zu versehen. In den meisten Projekten gilt: mit FIXME werden Stellen markiert, die noch vor
36 | der Veröffentlichung eines Programms zu beheben sind. Lediglich mit TODO markierte Stellen können länger im Programm
37 | verbleiben. Wichtig bleibt: größere Änderungswünsche sollten immer in einem Issue Tracker verwaltet werden, damit diese
38 | auch mit in die Planung einfließen können.
39 |
40 | Auf der anderen Seite sind Kommentare zur Versionshistorie einer Datei nicht sinnvoll, diese werden sowieso in der
41 | Versionsverwaltung abgelegt und sind somit redundant.
42 |
43 | ## JavaDoc
44 |
45 | JavaDoc wird genutzt um die öffentliche Schnittstelle eines Programms zu dokumentieren. Diese Kommentare sind unerlässlich
46 | und müssen für alle Klassen und Methoden verfasst werden, die mindestens die Sichtbarkeit `protected` haben. Wird eine Klasse
47 | serialisiert (z.B. wenn sie die Schnittstelle `Serializable` implementiert), dann müssen auch
48 | private Attribute kommentiert werden, da in diesem Fall auch diese zur öffentlichen Schnittstelle einer Klasse gehören.
49 |
50 | Die [Java Bibliotheken](https://docs.oracle.com/javase/8/docs/api/) selbst bieten schöne Beispiele, wie solche Kommentare
51 | auszusehen haben und wie nützlich diese sind. Eine kleine Einführung zu diesem Thema ist auf den
52 | [Oracle Seiten](https://www.oracle.com/java/technologies/javase/javadoc.html) zu finden.
53 |
54 | JavaDoc Kommentare werden im aktiv geschrieben. Der erste Satz (der mit einem Punkt abgeschlossen wird) muss eine
55 | Zusammenfassung sein. Dieser wird im generierten HTML Dokument als Überschrift dargestellt. Das zu beschreibende Element
56 | wird dabei nicht noch einmal wiederholt, der Kommentar wird dadurch möglichst knapp.
57 | D.h. **"An ordered collection"** statt **"This interface defines an ordered collection"**, oder
58 | **"Returns whether this list contains no elements"** statt **"This method returns whether this list contains no elements"**.
59 | Die folgenden Sätze können dann das Element genauer beschreiben, hilfreich ist hierbei oft die Angabe eines
60 | Anwendungsbeispiels. Werden dabei Codestücke bzw. Variablen in die Beschreibung eingebettet, so müssen diese die Syntax
61 | `{@code ...}` nutzen. Werden Klassen oder Methoden referenziert, so werden diese mit der Syntax `{@link ...}` bzw.
62 | `{@linkplain ...}` eingefügt, nur so kann die IDE die Kommentare mit entsprechenden Hyperlinks anzeigen (*linkplain* verwendet
63 | einen Zeichensatz mit variabler, *link* mit fester Breite).
64 | Ganze Quelltext-Abschnitte, die über mehrere Zeilen gehen, werden mit der Syntax `
{@code ...}
` eingebettet.
65 |
66 | Beispiel:
67 |
68 | ```java
69 | /**
70 | * Checks if a {@link CharSequence} is empty ("") or {@code null}.
71 | *
72 | *
79 | *
80 | * @param text
81 | * the text to check, may be {@code null}
82 | * @return {@code true} if the text is empty or {@code null}
83 | * @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
84 | */
85 | public static boolean isEmpty(final CharSequence text) {
86 | return text == null || text.length() == 0;
87 | }
88 |
89 | ```
90 |
--------------------------------------------------------------------------------
/doc/Namensgebung.md:
--------------------------------------------------------------------------------
1 | # Namensgebung
2 |
3 | Bezeichner (*Identifier*) sind in Java beliebig lang und bestehen aus einer Zeichenkette
4 | von großen und kleinen Buchstaben, Ziffern oder dem Underscore `_`. Hierbei werden Groß und Kleinschreibung
5 | unterschieden (klein ist nicht Klein). Folgende Einschränkungen sind dabei zu beachten:
6 | Das erste Zeichen darf keine Ziffer sein und
7 | [ca. 50 Schlüsselwörter](http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html)
8 | sind vom System reserviert und für eigenen Namen verboten, z.B. class, import, public, etc.
9 |
10 | Neben dieser formalen Syntax haben sich folgende Konventionen eingebürgert.
11 |
12 | ## Allgemeine Konventionen
13 |
14 | Bezeichner in Java verwenden American English und nutzen damit automatisch nur ASCII Zeichen (keine Umlaute). Der
15 | Underscore `_` wird i.A. nicht verwendet. Auch angehängte Zahlen sind untypisch und meistens ein Zeichen für schlechten
16 | Stil (*Code Smell* [6]).
17 |
18 | Bezeichner sind stets aussagekräftig und bestehen damit oft aus mehreren Teilwörtern. Wir verwenden dann die Schreibweise
19 | [CamelCase](https://en.wikipedia.org/wiki/Camel_case). Bezeichner nutzen i.A. keine Abkürzungen, die Autovervollständigung der
20 | Entwicklungsumgebungen ergänzt lange Bezeichner komfortabel. Wenn ein Bezeichner doch einmal eine Abkürzung enthält,
21 | dann wird auch hier nur der erste Buchstabe groß geschrieben, z.B. `loadXmlDocument`, `writeAsJson`.
22 |
23 | Zum Thema Abkürzung noch ein schönes Zitat von Ken Thompson auf die Frage was er ändern würde, wenn er UNIX
24 | nochmals erfinden dürfte: “I‘d spell creat with an e.“
25 |
26 | Zum Thema Namensgebung finden sich einige schöne Anti-Beispiele im Essay
27 | ["How To Write Unmaintainable Code"](https://github.com/Droogans/unmaintainable-code) von Roedy Green.
28 |
29 | ### Methodennamen
30 |
31 | Methodennamen enthalten ein Verb im Aktiv, z.B. `computeSum`, `moveForward`, `turnRight`, `compareToIgnoreCase`. Sie beginnen
32 | immer mit einem kleinen Buchstaben. Liefert eine Methode einen `boolean` zurück, dann beginnt der Name i.A. mit einem
33 | `is`, z.B. `isEmpty`, `isTreeFront`, `isNotRunning`, etc. Macht das grammatikalisch keinen Sinn, kann statt dessen auch
34 | `can`, `has`, `should` oder ähnliches verwendet werden. Hauptsache ist, dass sich boolesche Methoden wie eine Frage lesen: d.h. `equals`,
35 | `exists`, `contains` etc. sind auch in Ordnung.
36 |
37 | ## Variablennamen
38 |
39 | Variablennamen beginnen mit einem kleinen Buchstaben. Variablen vom Typ `boolean` nutzen meist den Präfix `is`, siehe
40 | Abschnitt zu booleschen Methodennamen. Alle anderen Variablennamen sind im Allgemeinen ein Substantiv, da ein Objekt
41 | gespeichert wird. Werden in einer Variablen mehrere Objekte gespeichert (Array, Listen, etc.), dann wird die Mehrzahl
42 | verwendet. Beispiele: counter, isLeaf, numberOfTrees, months, etc.
43 |
44 | ## Klassennamen
45 |
46 | Klassennamen sind ein Substantiv und beginnen mit einem großen Buchstaben. Vor oder nach dem Substantiv können
47 | ggf. weitere beschreibende Wörter verwendet werden, z.B. `Counter`, `LimitedCounter`, `OpenCounter`, `HashMap`,
48 | `ConcurrentHashMap`. Abstrakte Klassen halten sich i.A. auch an dieses Schema - manchmal macht es aber auch Sinn
49 | diese durch den Präfix `Abstract` als solche zu markieren, z.B. `AbstractList` oder `AbstractDocument`. Testklassen
50 | haben immer den Suffix `Test` nach dem eigentlichen Namen der Klasse, die getestet werden soll, z.B. `CounterTest`
51 | oder `HashMapTest`.
52 |
53 | ## Interfacenamen
54 |
55 | Interfacenamen sind entweder ein Substantiv (siehe Abschnitt Klassennamen) oder ein Adverb
56 | und beginnen mit einem großen Buchstaben. Vor oder nach dem Substantiv bzw. Adverb können
57 | ggf. weitere beschreibende Wörter verwendet werden, z.B. `Counter`, `Observable`, `WeakListener`,
58 | `Set`, `SortedSet`. Manche Projekte (z.B. Eclipse) verwenden das Anti-Pattern der
59 | [Ungarischen Notation](http://msdn.microsoft.com/de-de/library/aa260976(VS.60).aspx)
60 | und stellen jedem Interface den Präfix `I` voraus. Das ist nur in seltenen Fällen sinnvoll und sollte
61 | vermieden werden.
62 |
--------------------------------------------------------------------------------
/doc/State-Based-Vs-Interaction-Based.md:
--------------------------------------------------------------------------------
1 | # State Based vs. Interaction Based Testing
2 |
3 | Prinzipiell gibt es zwei Varianten des Testings: das **State Based Testing** und das **Interaction Based Testing**.
4 |
5 | ## State Based Testing
6 |
7 | Beim **State Based Testing** wird das Testobjekt nach Aufruf der zu
8 | testenden Methoden durch Abfrage seines internen Zustands verifiziert. Analog dazu kann natürlich auch der Zustand
9 | der im Test verwendeten Parameter bzw. Rückgabewerte analysiert werden. Die meisten Tests eines Projekts
10 | laufen nach diesem Muster ab und können folgendermaßen formuliert werden:
11 |
12 | ```java
13 | /** [Kurze Beschreibung: was genau macht der Test] */
14 | @Test
15 | void should[restlicher Methodenname der den Test fachlich beschreibt]() {
16 | // Given
17 | [Test Setup: Erzeugung der Parameter, die das SUT zum Erzeugen bzw. beim Aufruf benötigt]
18 | [Erzeugung des SUT]
19 | // When
20 | [Aufruf der zu testenden Methoden]
21 | // Then
22 | [Verifikation des Zustands des SUT bzw. von Parametern oder Rückgabewerten mittels AssertJ]
23 | }
24 | ```
25 |
26 | Die folgenden beiden Tests aus diesem Projekt zeigen die zwei unterschiedlichen Varianten des State Based Testing.
27 |
28 | ### Verifizieren der Rückgabewerte
29 |
30 | Im folgenden Test wird der Rückgabewert einer Methode überprüft.
31 |
32 | ```java
33 | @Test
34 | void shouldConvertToAbsolute() {
35 | PathUtil pathUtil = new PathUtil();
36 |
37 | assertThat(pathUtil.createAbsolutePath(null, FILE_NAME)).isEqualTo(FILE_NAME);
38 | assertThat(pathUtil.createAbsolutePath("", FILE_NAME)).isEqualTo(FILE_NAME);
39 | assertThat(pathUtil.createAbsolutePath("/", FILE_NAME)).isEqualTo("/" + FILE_NAME);
40 | assertThat(pathUtil.createAbsolutePath("/tmp", FILE_NAME)).isEqualTo("/tmp/" + FILE_NAME);
41 | assertThat(pathUtil.createAbsolutePath("/tmp/", FILE_NAME)).isEqualTo("/tmp/" + FILE_NAME);
42 | }
43 | ```
44 |
45 | ### Verifizieren der Objektzustands
46 |
47 | Im folgenden Test wird der Zustand eines Objekts überprüft.
48 |
49 | ```java
50 | @Test
51 | void shouldCreateSimpleTreeStringsWithBuilder() {
52 | TreeStringBuilder builder = new TreeStringBuilder();
53 |
54 | TreeString foo = builder.intern("foo");
55 |
56 | assertThat(foo).hasToString("foo");
57 | assertThat(foo.getLabel()).isEqualTo("foo");
58 | }
59 |
60 | ```
61 |
62 | ## Interaction Based Testing
63 |
64 | Im Gegensatz dazu wird beim **Interaction Based Testing** nicht der Zustand des SUT analysiert. Statt dessen werden die
65 | Aufrufe aller am Test beteiligten Objekte mit einem Mocking Framework wie [Mockito](https://site.mockito.org) überprüft.
66 | D.h. hier steht nicht der Zustand des Testobjekts im Vordergrund, sondern die Interaktion mit beteiligten Objekten. Ein
67 | typischer Testfall nach dem Interaction Based Testing ist folgendermaßen aufgebaut:
68 |
69 | ```java
70 | /** [Kurze Beschreibung: was genau macht der Test] */
71 | @Test
72 | void should[restlicher Methodenname der den Test fachliche beschreibt]() {
73 | // Given
74 | [Test Setup 1: Erzeugung der Mocks, die zur Verifikation benötigt werden]
75 | [Test Setup 2: Erzeugung der Stubs, die das SUT zum Erzeugen bzw. beim Aufruf benötigt]
76 | [Erzeugung des SUT]
77 | // When
78 | [Aufruf der zu testenden Methoden]
79 | // Then
80 | [Verifikation des Zustands der Mocks]
81 | }
82 | ```
83 |
84 | Ein typisches Beispiel für solch einen Test ist in der folgenden Klasse zu finden:
85 |
86 | ```java
87 | package edu.hm.hafner.util;
88 |
89 | import java.io.PrintStream;
90 |
91 | import org.junit.jupiter.api.Test;
92 |
93 | import static java.util.Arrays.*;
94 | import static java.util.Collections.*;
95 | import static org.mockito.Mockito.*;
96 |
97 | /**
98 | * Tests the class {@link PrefixLogger}.
99 | */
100 | class PrefixLoggerTest {
101 | private static final String LOG_MESSAGE = "Hello PrefixLogger!";
102 | private static final String PREFIX = "test";
103 | private static final String EXPECTED_PREFIX = "[test]";
104 |
105 | @Test
106 | void shouldLogSingleAndMultipleLines() {
107 | PrintStream printStream = mock(PrintStream.class);
108 | PrefixLogger logger = new PrefixLogger(printStream, PREFIX);
109 |
110 | logger.log(LOG_MESSAGE);
111 |
112 | verify(printStream).println(EXPECTED_PREFIX + " " + LOG_MESSAGE);
113 | }
114 | }
115 | ```
116 |
--------------------------------------------------------------------------------
/doc/dependency-graph.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 | skinparam defaultTextAlignment center
3 | skinparam rectangle {
4 | BackgroundColor<> beige
5 | BackgroundColor<> lightGreen
6 | BackgroundColor<> lightBlue
7 | BackgroundColor<> lightGray
8 | }
9 | rectangle "codingstyle\n\n5.15.0-SNAPSHOT" as edu_hm_hafner_codingstyle_jar
10 | rectangle "spotbugs-annotations\n\n4.9.3" as com_github_spotbugs_spotbugs_annotations_jar
11 | rectangle "error_prone_annotations\n\n2.38.0" as com_google_errorprone_error_prone_annotations_jar
12 | rectangle "commons-lang3\n\n3.17.0" as org_apache_commons_commons_lang3_jar
13 | rectangle "commons-io\n\n2.19.0" as commons_io_commons_io_jar
14 | edu_hm_hafner_codingstyle_jar -[#000000]-> com_github_spotbugs_spotbugs_annotations_jar
15 | edu_hm_hafner_codingstyle_jar -[#000000]-> com_google_errorprone_error_prone_annotations_jar
16 | edu_hm_hafner_codingstyle_jar -[#000000]-> org_apache_commons_commons_lang3_jar
17 | edu_hm_hafner_codingstyle_jar -[#000000]-> commons_io_commons_io_jar
18 | @enduml
--------------------------------------------------------------------------------
/doc/images/actions-annotation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/actions-annotation.png
--------------------------------------------------------------------------------
/doc/images/actions-autograding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/actions-autograding.png
--------------------------------------------------------------------------------
/doc/images/actions-buildlog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/actions-buildlog.png
--------------------------------------------------------------------------------
/doc/images/actions-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/actions-overview.png
--------------------------------------------------------------------------------
/doc/images/build-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/build-result.png
--------------------------------------------------------------------------------
/doc/images/gitlab-autograding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/gitlab-autograding.png
--------------------------------------------------------------------------------
/doc/images/gitlab-commit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/gitlab-commit.png
--------------------------------------------------------------------------------
/doc/images/gitlab-console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/gitlab-console.png
--------------------------------------------------------------------------------
/doc/images/quality-monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/uhafner/codingstyle/d3fffc46e4368574d8432d6c3595e9df09a59822/doc/images/quality-monitor.png
--------------------------------------------------------------------------------
/doc/uml/activity-diagram.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | skinparam activity {
4 | BackgroundColor #eaeaea
5 | BorderColor #a0a0a0
6 | BorderColor black
7 | ArrowColor black
8 | ArrowThickness 2
9 | FontName Arial Unicode MS
10 | FontSize 20
11 | }
12 |
13 | sprite $rake [16x19/8] {
14 | 0000000000000000
15 | 0000000jj0000000
16 | 0000000jj0000000
17 | 0005555jj5555000
18 | 000jjeejjeejj000
19 | 000jj00jj00jj000
20 | 000jj00jj00jj000
21 | 0000000000000000
22 | }
23 |
24 | skinparam ArrowColor black
25 | skinparam ArrowThickness 2
26 |
27 | skinparam activityDiamondBackgroundColor #f5f5f5
28 | skinparam activityDiamondFontColor #black
29 | skinparam activityDiamondBorderColor black
30 | skinparam activityDiamondFont Arial Unicode MS
31 | skinparam activityArrowFontSize 20
32 | skinparam activityArrowFont Arial Unicode MS
33 |
34 | |Partition 1|
35 | start
36 | repeat
37 | :Erste Aktion;
38 | if( Frage? ) then ([true]\t)
39 | :Alternative Links;
40 | else (\t[false])
41 | :Alternative Rechts;
42 | endif
43 | |Partition 2|
44 | :Zweite Aktion;
45 | repeat while () is (\t [Bedingung 1])
46 | -> [Bedingung 2];
47 | :Weitere Aktion;
48 | :Weitere Aktivität <$rake>;
49 | :Objekt]
50 | |Partition 1|
51 | fork
52 | :Parallele Aktion 1;
53 | fork again
54 | :Parallele Aktion 2;
55 | fork end
56 | stop
57 | @enduml
58 |
--------------------------------------------------------------------------------
/doc/uml/class-diagram-domain-model.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | skinparam package {
4 | BackgroundColor #eaeaea
5 | BorderColor #a0a0a0
6 | BackgroundColor<> gold
7 | BorderColor black
8 | ArrowColor black
9 | FontName Arial Unicode MS
10 | FontSize 20
11 | }
12 |
13 | skinparam class {
14 | BackgroundColor #eaeaea
15 | BorderColor #a0a0a0
16 | BackgroundColor<> gold
17 | BorderColor black
18 | ArrowColor black
19 | FontName Arial Unicode MS
20 | FontSize 20
21 | }
22 | skinparam classFontSize 24
23 | skinparam classAttributeIconSize 0
24 | skinparam defaultFontSize 20
25 |
26 | skinparam ArrowColor black
27 | skinparam ArrowThickness 2
28 |
29 | hide circle
30 |
31 | class Entität {
32 | -attributName1: Datentyp
33 | -attributName2: String
34 | -schlüssel<>: String
35 | }
36 |
37 | class "Abgeleitete Entität" as A
38 | class "Verbundene Entität" as B
39 |
40 | class A {
41 | -attributSubEntität: Datentyp
42 | }
43 |
44 | class B {
45 | -attribut: Datentyp
46 | -schlüssel<>: Datentyp
47 | }
48 |
49 | class Weitere {
50 | -attribut: Datentyp
51 | -schlüssel<>: Datentyp
52 | }
53 |
54 | class Assoziationsentität {
55 | -beziehungsAttribut: Datentyp
56 | }
57 |
58 | Entität "0..1" - "*" B : \t\t
59 | Entität <|-- A
60 | A o- Aggregation : rollenName >
61 | B *- Komposition : > rollenName
62 |
63 | (Komposition, Weitere) . Assoziationsentität
64 |
65 | class " Mehrfach verbundene Entität " as Beziehung
66 |
67 | Weitere -left- Beziehung : Rollenname 1 \t \t\t >
68 | Weitere -left- Beziehung: Rollenname 2 \t \t \t \t >
69 |
70 | @enduml
71 |
--------------------------------------------------------------------------------
/doc/uml/class-diagram-technical.puml:
--------------------------------------------------------------------------------
1 | @startuml
2 |
3 | skinparam package {
4 | BackgroundColor #efefef
5 | BorderColor #a0a0a0
6 | BackgroundColor<> gold
7 | BorderColor black
8 | ArrowColor black
9 | FontName Arial Unicode MS
10 | FontSize 20
11 | }
12 |
13 | skinparam class {
14 | BackgroundColor #white
15 | BorderColor #f4f4f4
16 | BackgroundColor<> gold
17 | BorderColor black
18 | ArrowColor black
19 | FontName Arial Unicode MS
20 | FontSize 20
21 | }
22 |
23 | skinparam note {
24 | BackgroundColor LightBlue
25 | BorderColor #a0a0a0
26 | FontName Arial
27 | FontSize 14
28 | FontColor black
29 | RoundCorner 15
30 | LineType solid
31 | }
32 |
33 | skinparam classFontSize 24
34 | skinparam classAttributeIconSize 0
35 | skinparam defaultFontSize 20
36 |
37 | skinparam ArrowColor black
38 | skinparam ArrowThickness 2
39 |
40 | hide circle
41 |
42 | package java.util {
43 | class Observable {
44 | - changed: boolean
45 | +registerObserver(o: Observer)
46 | +unregisterObserver(o: Observer)
47 | #notifyObservers()
48 | }
49 |
50 | interface Observer <> {
51 | +update() {abstract}
52 | }
53 | }
54 |
55 | class ConcreteObservable {
56 | -concreteState: State
57 | +getState(): State
58 | +setState(s: State)
59 | }
60 |
61 | Observable <|-- ConcreteObservable
62 |
63 | hide interface fields
64 |
65 | abstract class AbstractObserver < T extends Observer > {
66 | +update()
67 | #handleUpdate(o: Observer) {abstract}
68 | }
69 |
70 | class ConcreteObserver {
71 | #handleUpdate(o: Observer)
72 | }
73 |
74 | class StringUtils {
75 | +isEmpty(value: String) {static}
76 | }
77 |
78 | Observable o- Observer : \t\t
79 |
80 | Observer <|.. AbstractObserver
81 | AbstractObserver <|-- ConcreteObserver : <> \n ConcreteObserver>
82 | ConcreteObservable <-left- ConcreteObserver : \t\t
83 | ConcreteObservable .down.> StringUtils : <