[BAEL-4381] Intro to ArchUnit

This commit is contained in:
Philippe 2020-07-28 10:26:00 -03:00
parent 0cade733ca
commit 2911201832
9 changed files with 349 additions and 3 deletions

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2020-07-26T17:57:12.410Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.5.1 Chrome/83.0.4103.122 Electron/9.1.1 Safari/537.36" etag="taZU8w0iOhZ7shLjO8K-" version="13.5.1" type="device"><diagram name="Page-1" id="b5b7bab2-c9e2-2cf4-8b2a-24fd1a2a6d21">7VjbctowEP0aP9LBNgb3sSa3BzJNJ+2kk5eMsBdbrax1ZUEgX1/Jlm84YWgbKL3wwFhHa3l99pyVwHKn6fpSkCy5xgiY5QyjteWeWY7jj331rYFNCXjOsARiQaMSshvglj6BAauwJY0g7wRKRCZp1gVD5BxC2cGIEPjYDVsg6z41IzH0gNuQsD56RyOZGNQev20mroDGiXm070zKiTkJv8YCl9w8jyOHciYl1TLmHfOERPjYgtxzy50KRFlepespMM1qxVh538ULs3XKArjc54YrsrkffLj+Bp8ePr+/GTw409XdwKyyImxpqEg3JMsYDYmkyE3mclMRpV4i05eaYRCWGyyQy1szb6txnpGQ8vgjZhoYKkSSecXpyIxrKu1RCdxgTovnuWcMFmomSGTKzJIrEFLlw94xGusIqdcOiBmZeJ3HBUkp0wqcLUMaEZX5FHmOOreAkTmwoK7WFBmK4pXcRfHRS1DGWvhF8VF4n+iKNZUYrFuQIf4SMAUpNiqkmvWMCIw/7EoUj43aJr7BkpbQRq4BiVF4XK/dlFpdmGr/QOUnvcpbzpikmlomi7dujyLIgEd5DcadEDPa0gpEymNmiEImGCMn7LxBg6IUoLPUwmhiZljKR4FfQMqNaRhkKbErjYjkSXG//ToSeLHUOS5FCDvodE3XIiIGuSPOK+M0NzuFI4ApB666/enVReD2RJCDWNEQTsL4bUMWjbXn+udbwyGFsL/nPX/L837f8874Gc/bB/P8+N/26GhPj7on5VH/KI16ponvFq7yWqiILiy/7baURlGpEcjpE5kX62mVZEi5LHjwAss7O1Tdd2m859P68Gjy7JzCnvPvYPhG7dOmX+9darPcjWagtf9POq1gYHvdFXCxyJUkt6VSJ/Xz6hn11JOpaikKT+d892e3eXuyR5v3jtrmvX7NQeQ0l8BPZGc/Vn0PeKTf3t5Hw9++vVe/pk/Z7P+d/UsV7v9eP6UD+19o64Oe2tWw+f+n3PGbv9fc8+8=</diagram></mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>libraries-testing</artifactId>
<name>libraries-testing</name>
@ -158,6 +158,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>${archunit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -193,7 +200,7 @@
<properties>
<asciidoctor.version>1.5.7.1</asciidoctor.version>
<serenity.version>1.9.9</serenity.version>
<serenity.version>1.9.9</serenity.version>
<serenity.jbehave.version>1.9.0</serenity.jbehave.version>
<serenity.jira.version>1.9.0</serenity.jira.version>
<serenity.plugin.version>1.9.27</serenity.plugin.version>
@ -210,6 +217,7 @@
<maven-compiler-plugin.target>1.8</maven-compiler-plugin.target>
<maven-compiler-plugin.source>1.8</maven-compiler-plugin.source>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<archunit.version>0.14.1</archunit.version>
</properties>
</project>

View File

@ -0,0 +1,49 @@
/**
*
*/
package com.baldung.archunit.smurfs.persistence;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeMap;
import com.baldung.archunit.smurfs.persistence.domain.Smurf;
import static java.util.stream.Collectors.toList;
/**
* @author Philippe
*
*/
public class SmurfsRepository {
private static Map<String,Smurf> smurfs = Collections.synchronizedMap(new TreeMap<>());
static {
// Just a few here. A full list can be found
// at https://smurfs.fandom.com/wiki/List_of_Smurf_characters
smurfs.put("Papa", new Smurf("Papa", true, true));
smurfs.put("Actor", new Smurf("Actor", true, true));
smurfs.put("Alchemist", new Smurf("Alchemist", true, true));
smurfs.put("Archeologist", new Smurf("Archeologist", true, true));
smurfs.put("Architect", new Smurf("Architect", true, true));
smurfs.put("Baby", new Smurf("Baby", true, true));
smurfs.put("Baker", new Smurf("Baker", true, true));
smurfs.put("Baker", new Smurf("Baker", true, true));
}
public SmurfsRepository() {
}
public List<Smurf> findAll() {
return Collections.unmodifiableList(smurfs.values().stream().collect(toList()));
}
public Optional<Smurf> findByName(String name) {
return Optional.of(smurfs.get(name));
}
}

View File

@ -0,0 +1,64 @@
/**
*
*/
package com.baldung.archunit.smurfs.persistence.domain;
/**
* @author Philippe
*
*/
public class Smurf {
private String name;
private boolean comic;
private boolean cartoon;
public Smurf() {}
public Smurf(String name, boolean comic, boolean cartoon) {
this.name = name;
this.comic = comic;
this.cartoon = cartoon;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the commic
*/
public boolean isComic() {
return comic;
}
/**
* @param commic the commic to set
*/
public void setCommic(boolean comic) {
this.comic = comic;
}
/**
* @return the cartoon
*/
public boolean isCartoon() {
return cartoon;
}
/**
* @param cartoon the cartoon to set
*/
public void setCartoon(boolean cartoon) {
this.cartoon = cartoon;
}
}

View File

@ -0,0 +1,27 @@
package com.baldung.archunit.smurfs.presentation;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baldung.archunit.smurfs.service.SmurfsService;
import com.baldung.archunit.smurfs.service.dto.SmurfDTO;
@RequestMapping(value = "/smurfs", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@RestController
public class SmurfsController {
private SmurfsService smurfs;
public SmurfsController(SmurfsService smurfs) {
this.smurfs = smurfs;
}
@GetMapping
public List<SmurfDTO> getSmurfs() {
return smurfs.findAll();
}
}

View File

@ -0,0 +1,41 @@
/**
*
*/
package com.baldung.archunit.smurfs.service;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
import com.baldung.archunit.smurfs.persistence.SmurfsRepository;
import com.baldung.archunit.smurfs.persistence.domain.Smurf;
import com.baldung.archunit.smurfs.service.dto.SmurfDTO;
/**
* @author Philippe
*
*/
@Component
public class SmurfsService {
private SmurfsRepository repository;
public SmurfsService(SmurfsRepository repository) {
this.repository = repository;
}
public List<SmurfDTO> findAll() {
return repository.findAll()
.stream()
.map(SmurfsService::toDTO)
.collect(Collectors.toList());
}
public static SmurfDTO toDTO(Smurf smurf) {
return new SmurfDTO(smurf.getName(),smurf.isComic(), smurf.isCartoon());
}
}

View File

@ -0,0 +1,64 @@
/**
*
*/
package com.baldung.archunit.smurfs.service.dto;
import com.baldung.archunit.smurfs.persistence.domain.Smurf;
/**
* @author Philippe
*
*/
public class SmurfDTO {
private String name;
private boolean comic;
private boolean cartoon;
public SmurfDTO() {}
public SmurfDTO(String name, boolean comic, boolean cartoon) {
this.name = name;
this.comic = comic;
this.cartoon = cartoon;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the commic
*/
public boolean isComic() {
return comic;
}
/**
* @param commic the commic to set
*/
public void setCommic(boolean comic) {
this.comic = comic;
}
/**
* @return the cartoon
*/
public boolean isCartoon() {
return cartoon;
}
/**
* @param cartoon the cartoon to set
*/
public void setCartoon(boolean cartoon) {
this.cartoon = cartoon;
}
}

View File

@ -0,0 +1,92 @@
/**
*
*/
package com.baeldung.archunit.smurfs;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.library.Architectures.LayeredArchitecture;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
/**
* @author Philippe
*
*/
public class SmurfsArchUnitTest {
@Test
public void givenPresentationLayerClasses_thenWrongCheckFails() {
JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
ArchRule r1 = classes()
.that()
.resideInAPackage("..presentation..")
.should()
.onlyDependOnClassesThat()
.resideInAPackage("..service..");
assertThrows(AssertionError.class, ()-> r1.check(jc)) ;
}
@Test
public void givenPresentationLayerClasses_thenCheckWithFrameworkDependenciesSuccess() {
JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
ArchRule r1 = classes()
.that()
.resideInAPackage("..presentation..")
.should()
.onlyDependOnClassesThat()
.resideInAnyPackage("..service..", "java..", "javax..", "org.springframework..");
r1.check(jc);
}
@Test
public void givenPresentationLayerClasses_thenNoPersistenceLayerAccess() {
JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
ArchRule r1 = noClasses()
.that()
.resideInAPackage("..presentation..")
.should()
.dependOnClassesThat()
.resideInAPackage("..persistence..");
r1.check(jc);
}
@Test
public void givenApplicationClasses_thenNoLayerViolationsShouldExist() {
JavaClasses jc = new ClassFileImporter().importPackages("com.baldung.archunit.smurfs");
LayeredArchitecture arch = layeredArchitecture()
// Define layers
.layer("Presentation").definedBy("..presentation..")
.layer("Service").definedBy("..service..")
.layer("Persistence").definedBy("..persistence..")
// Add constraints
.whereLayer("Presentation").mayNotBeAccessedByAnyLayer()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Presentation")
.whereLayer("Persistence").mayOnlyBeAccessedByLayers("Service");
arch.check(jc);
}
}