|
| 1 | +:toc: macro |
| 2 | +toc::[] |
| 3 | +:idprefix: |
| 4 | +:idseparator: - |
| 5 | + |
| 6 | +## Hexagonal Architecture |
| 7 | +The sample app provided in this github repository is using a layered architecture. |
| 8 | +However, if you use hexagonal architecture instead, you can use https://www.archunit.org/userguide/html/000_Index.html#_onion_architecture[onion] instead. |
| 9 | +An example can be found in the https://github.com/TNG/ArchUnit-Examples/blob/main/example-plain/src/test/java/com/tngtech/archunit/exampletest/OnionArchitectureTest.java[official ArchUnit example repository]. |
| 10 | +
|
| 11 | +## Layered Architecture |
| 12 | +The layered architecture used in this sample app is based on the template of https://github.com/devonfw/java/blob/main/modules/ROOT/pages/architecture/layered_architecture.adoc[devonfw Java architecture]. |
| 13 | +It uses a classic three-layered architecture as descibed in the documentation linked above. |
| 14 | +ArchUnit provides the method `layeredArchitecture()` to easily construct rules to enforce a layered architecture. |
| 15 | +An example from this repository can be found https://github.com/devonfw-sample/archunit/blob/master/src/test/java/com/devonfw/sample/archunit/LayerRules.java[here]. |
| 16 | +
|
| 17 | +## ArchRule |
| 18 | +
|
| 19 | +### General |
| 20 | +
|
| 21 | +The class `ArchRuleDefinition` provides methods like `classes()`,`noClasses()`, `methods()` to construct an `ArchRule`. Examples can be found in in this https://github.com/devonfw-sample/archunit/blob/f547ddd11e3eabd2437c067a2196a49ef3505904/src/test/java/com/devonfw/sample/archunit/ThirdPartyRules.java#L44-L48[repository] or in the https://github.com/TNG/ArchUnit-Examples/tree/main/example-junit4/src/test/java/com/tngtech/archunit/exampletest/junit4[official example repository of ArchUnit]. |
| 22 | +
|
| 23 | +### Custom Rules |
| 24 | +
|
| 25 | +To implement a custom `ArchRule` `DescribedPredicate` and `ArchCondition` can be used like this: |
| 26 | +
|
| 27 | +`classes that ${PREDICATE} should ${CONDITION}` |
| 28 | +
|
| 29 | +The predicate filters a set of classes to verify some condition. |
| 30 | +An example can be found in this https://github.com/devonfw-sample/archunit/blob/master/src/test/java/com/devonfw/sample/archunit/AbstractRules.java#L25-L35[repository]. |
| 31 | +
|
| 32 | +The ArchCondition checks whether the filtered set satisfies a given condition. |
| 33 | +An example can be found in this https://github.com/devonfw-sample/archunit/blob/master/src/test/java/com/devonfw/sample/archunit/AbstractRules.java#L62-L86[repository]. |
| 34 | +
|
| 35 | +Further information is available in the https://www.archunit.org/userguide/html/000_Index.html#_creating_custom_rules[official user guide]. |
| 36 | +
|
| 37 | +### Error Message |
| 38 | +
|
| 39 | +Sometimes rules need custom error messages. `because()` and `as()` can be used to modify the output of error messages. Further information can be found in the https://www.archunit.org/userguide/html/000_Index.html#_controlling_the_rule_text[official user guide]. |
| 40 | +
|
| 41 | +`because("message")` concatenates the fluent API messages utilized by ArchUnit. |
| 42 | +
|
| 43 | +For example: |
| 44 | +[,java] |
| 45 | +---- |
| 46 | +noClasses() |
| 47 | + .that(DescribedPredicate("message1")) |
| 48 | + .should(ArchCondition("message2")) |
| 49 | + .because("message3") |
| 50 | +---- |
| 51 | +
|
| 52 | +would result in [red]#'no classes that "message1" should "message2", because "message3"'#. |
| 53 | +
|
| 54 | +Using `as("message")` enforces printing only the `message` string. |
| 55 | +
|
| 56 | +For example: |
| 57 | +[,java] |
| 58 | +---- |
| 59 | +noClasses() |
| 60 | + .that(DescribedPredicate("message1")) |
| 61 | + .should(ArchCondition("message2")) |
| 62 | + .as("message3") |
| 63 | +---- |
| 64 | +would result in [red]#'"message3"'#. |
| 65 | +
|
| 66 | +### Error Handling |
| 67 | +
|
| 68 | +If a rule failed unexpectedly, it might failed to check any classes, as that either means that no classes have been passed to the rule at all or that no classes passed the rule matching the `that()` clause. To allow rules being evaluated without checking any classes you can either use `ArchRule.allowEmptyShould(true)` on a single rule or set the configuration property `archRule.failOnEmptyShould = false` to change the behavior globally. |
| 69 | +
|
| 70 | +Further information can be found in the https://www.archunit.org/userguide/html/000_Index.html#_fail_rules_on_empty_should[official user guide]. |
0 commit comments