├── .gitignore
├── LICENSE.md
├── README.md
├── build.gradle
├── docs
└── onion-architecture.svg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
├── kotlin
│ └── com
│ │ └── github
│ │ └── spanierm
│ │ └── archunitjunit5kotlin
│ │ ├── ArchunitJunitKotlinApplication.kt
│ │ └── onion
│ │ ├── adapter
│ │ ├── cli
│ │ │ └── AdapterCli.kt
│ │ ├── persistence
│ │ │ └── AdapterPersistence.kt
│ │ └── rest
│ │ │ └── AdapterRest.kt
│ │ ├── application
│ │ └── Application.kt
│ │ └── domain
│ │ ├── model
│ │ └── DomainModel.kt
│ │ └── service
│ │ └── DomainService.kt
└── resources
│ └── application.properties
└── test
└── kotlin
└── com
└── github
└── spanierm
└── archunitjunit5kotlin
├── ArchUnitJunit5KotlinApplicationTests.kt
└── onion
└── OnionArchitectureTest.kt
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/linux,macos,kotlin,gradle,windows,eclipse,intellij+all,visualstudiocode
3 |
4 | ### Eclipse ###
5 |
6 | .metadata
7 | bin/
8 | tmp/
9 | *.tmp
10 | *.bak
11 | *.swp
12 | *~.nib
13 | local.properties
14 | .settings/
15 | .loadpath
16 | .recommenders
17 |
18 | # External tool builders
19 | .externalToolBuilders/
20 |
21 | # Locally stored "Eclipse launch configurations"
22 | *.launch
23 |
24 | # PyDev specific (Python IDE for Eclipse)
25 | *.pydevproject
26 |
27 | # CDT-specific (C/C++ Development Tooling)
28 | .cproject
29 |
30 | # CDT- autotools
31 | .autotools
32 |
33 | # Java annotation processor (APT)
34 | .factorypath
35 |
36 | # PDT-specific (PHP Development Tools)
37 | .buildpath
38 |
39 | # sbteclipse plugin
40 | .target
41 |
42 | # Tern plugin
43 | .tern-project
44 |
45 | # TeXlipse plugin
46 | .texlipse
47 |
48 | # STS (Spring Tool Suite)
49 | .springBeans
50 |
51 | # Code Recommenders
52 | .recommenders/
53 |
54 | # Annotation Processing
55 | .apt_generated/
56 |
57 | # Scala IDE specific (Scala & Java development for Eclipse)
58 | .cache-main
59 | .scala_dependencies
60 | .worksheet
61 |
62 | ### Eclipse Patch ###
63 | # Eclipse Core
64 | .project
65 |
66 | # JDT-specific (Eclipse Java Development Tools)
67 | .classpath
68 |
69 | # Annotation Processing
70 | .apt_generated
71 |
72 | .sts4-cache/
73 |
74 | ### Intellij+all ###
75 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
76 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
77 |
78 | # User-specific stuff
79 | .idea/**/workspace.xml
80 | .idea/**/tasks.xml
81 | .idea/**/usage.statistics.xml
82 | .idea/**/dictionaries
83 | .idea/**/shelf
84 |
85 | # Generated files
86 | .idea/**/contentModel.xml
87 |
88 | # Sensitive or high-churn files
89 | .idea/**/dataSources/
90 | .idea/**/dataSources.ids
91 | .idea/**/dataSources.local.xml
92 | .idea/**/sqlDataSources.xml
93 | .idea/**/dynamic.xml
94 | .idea/**/uiDesigner.xml
95 | .idea/**/dbnavigator.xml
96 |
97 | # Gradle
98 | .idea/**/gradle.xml
99 | .idea/**/libraries
100 |
101 | # Gradle and Maven with auto-import
102 | # When using Gradle or Maven with auto-import, you should exclude module files,
103 | # since they will be recreated, and may cause churn. Uncomment if using
104 | # auto-import.
105 | # .idea/modules.xml
106 | # .idea/*.iml
107 | # .idea/modules
108 |
109 | # CMake
110 | cmake-build-*/
111 |
112 | # Mongo Explorer plugin
113 | .idea/**/mongoSettings.xml
114 |
115 | # File-based project format
116 | *.iws
117 |
118 | # IntelliJ
119 | out/
120 |
121 | # mpeltonen/sbt-idea plugin
122 | .idea_modules/
123 |
124 | # JIRA plugin
125 | atlassian-ide-plugin.xml
126 |
127 | # Cursive Clojure plugin
128 | .idea/replstate.xml
129 |
130 | # Crashlytics plugin (for Android Studio and IntelliJ)
131 | com_crashlytics_export_strings.xml
132 | crashlytics.properties
133 | crashlytics-build.properties
134 | fabric.properties
135 |
136 | # Editor-based Rest Client
137 | .idea/httpRequests
138 |
139 | # Android studio 3.1+ serialized cache file
140 | .idea/caches/build_file_checksums.ser
141 |
142 | ### Intellij+all Patch ###
143 | # Ignores the whole .idea folder and all .iml files
144 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
145 |
146 | .idea/
147 |
148 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
149 |
150 | *.iml
151 | modules.xml
152 | .idea/misc.xml
153 | *.ipr
154 |
155 | ### Kotlin ###
156 | # Compiled class file
157 | *.class
158 |
159 | # Log file
160 | *.log
161 |
162 | # BlueJ files
163 | *.ctxt
164 |
165 | # Mobile Tools for Java (J2ME)
166 | .mtj.tmp/
167 |
168 | # Package Files #
169 | *.jar
170 | *.war
171 | *.nar
172 | *.ear
173 | *.zip
174 | *.tar.gz
175 | *.rar
176 |
177 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
178 | hs_err_pid*
179 |
180 | ### Linux ###
181 | *~
182 |
183 | # temporary files which can be created if a process still has a handle open of a deleted file
184 | .fuse_hidden*
185 |
186 | # KDE directory preferences
187 | .directory
188 |
189 | # Linux trash folder which might appear on any partition or disk
190 | .Trash-*
191 |
192 | # .nfs files are created when an open file is removed but is still being accessed
193 | .nfs*
194 |
195 | ### macOS ###
196 | # General
197 | .DS_Store
198 | .AppleDouble
199 | .LSOverride
200 |
201 | # Icon must end with two \r
202 | Icon
203 |
204 | # Thumbnails
205 | ._*
206 |
207 | # Files that might appear in the root of a volume
208 | .DocumentRevisions-V100
209 | .fseventsd
210 | .Spotlight-V100
211 | .TemporaryItems
212 | .Trashes
213 | .VolumeIcon.icns
214 | .com.apple.timemachine.donotpresent
215 |
216 | # Directories potentially created on remote AFP share
217 | .AppleDB
218 | .AppleDesktop
219 | Network Trash Folder
220 | Temporary Items
221 | .apdisk
222 |
223 | ### VisualStudioCode ###
224 | .vscode/*
225 | !.vscode/settings.json
226 | !.vscode/tasks.json
227 | !.vscode/launch.json
228 | !.vscode/extensions.json
229 |
230 | ### Windows ###
231 | # Windows thumbnail cache files
232 | Thumbs.db
233 | ehthumbs.db
234 | ehthumbs_vista.db
235 |
236 | # Dump file
237 | *.stackdump
238 |
239 | # Folder config file
240 | [Dd]esktop.ini
241 |
242 | # Recycle Bin used on file shares
243 | $RECYCLE.BIN/
244 |
245 | # Windows Installer files
246 | *.cab
247 | *.msi
248 | *.msix
249 | *.msm
250 | *.msp
251 |
252 | # Windows shortcuts
253 | *.lnk
254 |
255 | ### Gradle ###
256 | .gradle
257 | /build/
258 |
259 | # Ignore Gradle GUI config
260 | gradle-app.setting
261 |
262 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
263 | !gradle-wrapper.jar
264 |
265 | # Cache of project
266 | .gradletasknamecache
267 |
268 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
269 | # gradle/wrapper/gradle-wrapper.properties
270 |
271 |
272 | # End of https://www.gitignore.io/api/linux,macos,kotlin,gradle,windows,eclipse,intellij+all,visualstudiocode
273 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Markus Spanier
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Generic Architecture Tests with ArchUnit
2 |
3 | This repository shows generic examples for architecture tests using [ArchUnit].
4 | The tests are written in [Kotlin] using the [Junit5] testing framework.
5 |
6 |
7 | ## Onion Architecture
8 |
9 | The term **onion architecture** was first used by Jeffrey Palermo in his [onion architecture blog post](https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1/).
10 | Other names for similar architectural approaches are
11 | [hexagonal architecture](http://alistair.cockburn.us/Hexagonal+architecture),
12 | [ports and adapters](http://wiki.c2.com/?PortsAndAdaptersArchitecture), and
13 | [clean architecture](http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).
14 |
15 | We built [ArchUnit] tests for this architectural style in the [OnionArchitectureTest.kt](./src/test/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/OnionArchitectureTest.kt) file.
16 | It assumes a certain structure of all classes in the root package, i.e. the package of the `OnionArchitectureTest` class:
17 | * The core domain should be placed in the `domain` package.
18 | It contains the code logic of the application and is is independent of the infrastructure, adapters, frameworks in use, etc.
19 | We divide the package into two parts:
20 | * The `domain.model` package contains all models of the domain.
21 | Classes in this package do not have any dependencies to any other classes in the root package.
22 | * The `domain.service` package contains all logic of the domain.
23 | Classes in this package use the classes in `domain.model` package but do not have any dependencies to any other classes in the root package.
24 | * All application related parts, i.e. technical logic needed for the application to run and that are not part of the core domain,
25 | should be placed in the `application` package.
26 | Examples are global settings for date and time, e.g. a global `Clock` object, or security related configuration that is not part of an individual adapter.
27 | Classes in this package can access the `domain` package but do not depend on any other classes in the root package.
28 | * All external dependencies are placed in dedicated `adapter` packages.
29 | Examples are an `adapter.persistence` package that contains logic for storing and retrieving data from a data store
30 | or `adapter.cli` and `adapter.rest` packages for user interactions with the application.
31 | Classes in any `adapter` package can access all classes in the `domain` and `application` package
32 | but must not have dependencies on any other adapter packages.
33 |
34 |
35 |
36 |
37 |
38 | Note that the example code in the [onion](./src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion) package contain code that breaks the build.
39 | Uncomment the corresponding parts to make the tests pass.
40 |
41 |
42 | # Usage and Contribution
43 |
44 | Let us know if you like [ArchUnit] and use the templates in this repository by leaving a tweet mentioning [@archtests] and [@spanier_m].
45 |
46 | If you want to change parts of these examples, simply open a pull request with the changes and/or open an issue.
47 |
48 |
49 |
50 | [@archtests]: https://twitter.com/archtests
51 | [@spanier_m]: https://twitter.com/spanier_m
52 | [ArchUnit]: https://www.archunit.org/
53 | [Junit5]: https://junit.org/junit5/
54 | [Kotlin]: https://kotlinlang.org/
55 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | kotlinVersion = '1.3.61'
4 | springBootVersion = '2.2.5.RELEASE'
5 | archUnitVersion = '0.13.1'
6 | }
7 | repositories {
8 | jcenter()
9 | mavenCentral()
10 | }
11 | dependencies {
12 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}"
14 | classpath "org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}"
15 | }
16 | }
17 |
18 | repositories {
19 | jcenter()
20 | mavenCentral()
21 | }
22 |
23 | apply plugin: 'kotlin'
24 | apply plugin: 'kotlin-spring'
25 |
26 | apply plugin: 'io.spring.dependency-management'
27 | apply plugin: 'org.springframework.boot'
28 |
29 | group = 'com.github.spanierm.archunitjunit5kotlin'
30 | version = '0.0.1-SNAPSHOT'
31 | sourceCompatibility = 1.8
32 | compileKotlin {
33 | kotlinOptions {
34 | freeCompilerArgs = ['-Xjsr305=strict']
35 | jvmTarget = "1.8"
36 | }
37 | }
38 | compileTestKotlin {
39 | kotlinOptions {
40 | freeCompilerArgs = ['-Xjsr305=strict']
41 | jvmTarget = "1.8"
42 | }
43 | }
44 |
45 | dependencyManagement {
46 | imports {
47 | mavenBom 'org.junit:junit-bom:5.3.1'
48 | }
49 | }
50 |
51 | dependencies {
52 | implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
53 | implementation 'org.jetbrains.kotlin:kotlin-reflect'
54 |
55 | implementation 'org.springframework.boot:spring-boot-autoconfigure'
56 |
57 | testImplementation 'org.springframework.boot:spring-boot-starter-test', {
58 | exclude module: 'junit'
59 | }
60 | testImplementation "com.tngtech.archunit:archunit-junit5-api:${archUnitVersion}"
61 | testImplementation "com.tngtech.archunit:archunit-junit5-engine:${archUnitVersion}"
62 | testImplementation 'org.junit.jupiter:junit-jupiter-api'
63 | testImplementation 'org.junit.jupiter:junit-jupiter-params'
64 | testRuntime 'org.junit.jupiter:junit-jupiter-engine'
65 | testRuntime 'org.junit.platform:junit-platform-engine'
66 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
67 | }
68 |
69 | test {
70 | useJUnitPlatform()
71 | }
72 |
--------------------------------------------------------------------------------
/docs/onion-architecture.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spanierm42/archunit-junit5-kotlin/1e5c190b74a43785c2dabc8a8f689e74ac25e368/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Feb 06 12:27:20 CET 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save ( ) {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'archunit-junit5-kotlin'
2 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/ArchunitJunitKotlinApplication.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin
2 |
3 | import org.springframework.boot.autoconfigure.SpringBootApplication
4 | import org.springframework.boot.runApplication
5 |
6 | @SpringBootApplication
7 | class ArchunitJunitKotlinApplication
8 |
9 | fun main(args: Array) {
10 | runApplication(*args)
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/adapter/cli/AdapterCli.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.adapter.cli
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.adapter.persistence.AdapterPersistence
4 |
5 | class AdapterCli {
6 | val forbiddenTransitivePackageCycle = AdapterPersistence()
7 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/adapter/persistence/AdapterPersistence.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.adapter.persistence
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.adapter.rest.AdapterRest
4 |
5 | class AdapterPersistence {
6 | val forbiddenDirectPackageCycleWithAdapterRest = AdapterRest()
7 | val forbiddenTransitivePackageCycle = AdapterRest()
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/adapter/rest/AdapterRest.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.adapter.rest
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.adapter.cli.AdapterCli
4 | import com.github.spanierm.archunitjunit5kotlin.onion.adapter.persistence.AdapterPersistence
5 |
6 | class AdapterRest {
7 | val forbiddenOtherAdapterAccess = AdapterPersistence()
8 | val forbiddenTransitivePackageCycle = AdapterCli()
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/application/Application.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.application
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.adapter.persistence.AdapterPersistence
4 |
5 | class Application {
6 | val forbiddenAdapterAccess = AdapterPersistence()
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/domain/model/DomainModel.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.domain.model
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.domain.service.DomainService
4 |
5 | class DomainModel {
6 | val forbiddenDomainServiceAccess = DomainService()
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/domain/service/DomainService.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion.domain.service
2 |
3 | import com.github.spanierm.archunitjunit5kotlin.onion.application.Application
4 |
5 | class DomainService {
6 | val forbiddenApplicationAccess = Application()
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spanierm42/archunit-junit5-kotlin/1e5c190b74a43785c2dabc8a8f689e74ac25e368/src/main/resources/application.properties
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/spanierm/archunitjunit5kotlin/ArchUnitJunit5KotlinApplicationTests.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin
2 |
3 | import org.junit.jupiter.api.Test
4 | import org.junit.jupiter.api.extension.ExtendWith
5 | import org.springframework.boot.test.context.SpringBootTest
6 | import org.springframework.test.context.junit.jupiter.SpringExtension
7 |
8 | @ExtendWith(SpringExtension::class)
9 | @SpringBootTest
10 | class ArchUnitJunit5KotlinApplicationTests {
11 | @Test
12 | fun contextLoads() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/kotlin/com/github/spanierm/archunitjunit5kotlin/onion/OnionArchitectureTest.kt:
--------------------------------------------------------------------------------
1 | package com.github.spanierm.archunitjunit5kotlin.onion
2 |
3 | import com.tngtech.archunit.junit.AnalyzeClasses
4 | import com.tngtech.archunit.junit.ArchTest
5 | import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses
6 | import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition
7 | import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices
8 | import org.junit.jupiter.api.TestInstance
9 |
10 | @TestInstance(TestInstance.Lifecycle.PER_CLASS)
11 | @AnalyzeClasses(packagesOf = [OnionArchitectureTest::class])
12 | internal class OnionArchitectureTest {
13 | @ArchTest
14 | val `there are no package cycles` =
15 | SlicesRuleDefinition.slices()
16 | .matching("$BASE_PACKAGE.(**)..")
17 | .should()
18 | .beFreeOfCycles()
19 |
20 | @ArchTest
21 | val `the domain model does not have outgoing dependencies` =
22 | noClasses()
23 | .that()
24 | .resideInAPackage("$DOMAIN_MODEL_PACKAGE..")
25 | .should()
26 | .accessClassesThat()
27 | .resideInAnyPackage("$DOMAIN_SERVICE_PACKAGE..", "$APPLICATION_PACKAGE..", "$ADAPTER_PACKAGE..")
28 |
29 | @ArchTest
30 | val `the domain does not access the application and adapters` =
31 | noClasses()
32 | .that()
33 | .resideInAPackage("$DOMAIN_PACKAGE..")
34 | .should()
35 | .accessClassesThat()
36 | .resideInAnyPackage("$APPLICATION_PACKAGE..", "$ADAPTER_PACKAGE..")
37 |
38 | @ArchTest
39 | val `the application does not access the adapters` =
40 | noClasses()
41 | .that()
42 | .resideInAPackage("$APPLICATION_PACKAGE..")
43 | .should()
44 | .accessClassesThat()
45 | .resideInAPackage("$ADAPTER_PACKAGE..")
46 |
47 | @ArchTest
48 | val `one adapter should not access another adapter` =
49 | slices()
50 | .matching("$ADAPTER_PACKAGE.(*)")
51 | .should().notDependOnEachOther()
52 |
53 | companion object {
54 | private val BASE_PACKAGE = OnionArchitectureTest::class.java.`package`.name
55 |
56 | private val DOMAIN_PACKAGE = "$BASE_PACKAGE.domain"
57 | private val DOMAIN_MODEL_PACKAGE = "$DOMAIN_PACKAGE.model"
58 | private val DOMAIN_SERVICE_PACKAGE = "$DOMAIN_PACKAGE.service"
59 |
60 | private val APPLICATION_PACKAGE = "$BASE_PACKAGE.application"
61 |
62 | private val ADAPTER_PACKAGE = "$BASE_PACKAGE.adapter"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------