[Java] Модульное тестирование архитектуры Spring Boot проекта с помощью ArchUnit (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
При создании программного обеспечения команды разработчиков обычно определяют набор руководящих принципов и соглашений по разработке кода, которые считаются лучшими практиками.Это методы, которые обычно документируются и доводятся до сведения всей команды разработчиков, которая их приняла. Однако во время разработки разработчики могут нарушить эти рекомендации, которые обнаруживаются во время ревью кода или с помощью инструментов проверки качества кода.Поэтому важным аспектом является автоматизация этих директив в максимально возможной степени по всей архитектуре проекта, позволяющая оптимизировать проверки.Мы можем реализовать эти рекомендации как проверяемые JUnit тесты с помощью ArchUnit. Это гарантирует, что сборка версии программного обеспечения будет прекращена в случае нарушения архитектуры.
ArchUnit — это бесплатная, простая и расширяемая библиотека для проверки архитектуры вашего Java кода для использования в любой простой среде модульного тестирования Java. То есть ArchUnit может проверять зависимости между пакетами и классами, уровенями и срезами, проверять циклические зависимости и многое другое. Он делает это путем анализа данного байт-кода Java и импорта всех классов в структуру кода Java.
ArchUnit позволяет вам реализовать правила для статических свойств архитектуры приложения в форме исполняемых тестов, таких как следующие:
- Проверки зависимостей пакетов
- Проверки зависимостей класса
- Проверки содержания классов и пакетов
- Проверки наследования
- Проверка аннотаций
- Проверка уровней
- Проверки цикла
Примечание переводчика. Эта заметка дополняет предыдущую на тему ArchUnit.
НачнемДля поддержки ArchUnit JUnit 5, просто добавьте следующую зависимость из Maven Central: pom.xmlXML
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>0.14.1</version>
<scope>test</scope>
</dependency>
build.gradleGroovy
dependencies {
testImplementation 'com.tngtech.archunit:archunit-junit5:0.14.1'
} }
Проверки зависимостей пакетовJava
class ArchunitApplicationTests {
private JavaClasses importedClasses;
@BeforeEach
public void setup() {
importedClasses = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.springboot.testing.archunit");
}
@Test
void servicesAndRepositoriesShouldNotDependOnWebLayer() {
noClasses()
.that().resideInAnyPackage("com.springboot.testing.archunit.service..")
.or().resideInAnyPackage("com.springboot.testing.archunit.repository..")
.should()
.dependOnClassesThat()
.resideInAnyPackage("com.springboot.testing.archunit.controller..")
.because("Services and repositories should not depend on web layer")
.check(importedClasses);
}
}
Сервисы и репозитории не должны взаимодействовать с веб-уровнем.Проверки зависимостей класса
class ArchunitApplicationTests {
private JavaClasses importedClasses;
@BeforeEach
public void setup() {
importedClasses = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.springboot.testing.archunit");
}
@Test
void serviceClassesShouldOnlyBeAccessedByController() {
classes()
.that().resideInAPackage("..service..")
.should().onlyBeAccessed().byAnyPackage("..service..", "..controller..")
.check(importedClasses);
}
}
ArchUnit предлагает абстрактный API-интерфейс, похожий на DSL, который, в частности, может оценивать импортируемые классы. Доступ к сервисам должен осуществляться только контроллерами.Две точки представляют любое количество пакетов (сравните AspectJ Pointcuts). Соглашение об именованииJava
class ArchunitApplicationTests {
private JavaClasses importedClasses;
@BeforeEach
public void setup() {
importedClasses = new ClassFileImporter()
importedClasses = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.springboot.testing.archunit");
}
@Test
void serviceClassesShouldBeNamedXServiceOrXComponentOrXServiceImpl() {
classes()
.that().resideInAPackage("..service..")
.should().haveSimpleNameEndingWith("Service")
.orShould().haveSimpleNameEndingWith("ServiceImpl")
.orShould().haveSimpleNameEndingWith("Component")
.check(importedClasses);
}
@Test
void repositoryClassesShouldBeNamedXRepository() {
classes()
.that().resideInAPackage("..repository..")
.should().haveSimpleNameEndingWith("Repository")
.check(importedClasses);
}
@Test
void controllerClassesShouldBeNamedXController() {
classes()
.that().resideInAPackage("..controller..")
.should().haveSimpleNameEndingWith("Controller")
.check(importedClasses);
}
}
Общее правило — это соглашение об именах. Например, все имена сервис классов должны заканчиваться на Service, Component и т. д.Проверка аннотацийJava
class ArchunitApplicationTests {
private JavaClasses importedClasses;
@BeforeEach
public void setup() {
importedClasses = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.springboot.testing.archunit");
}
@Test
void fieldInjectionNotUseAutowiredAnnotation() {
noFields()
.should().beAnnotatedWith(Autowired.class)
.check(importedClasses);
}
@Test
void repositoryClassesShouldHaveSpringRepositoryAnnotation() {
classes()
.that().resideInAPackage("..repository..")
.should().beAnnotatedWith(Repository.class)
.check(importedClasses);
}
@Test
void serviceClassesShouldHaveSpringServiceAnnotation() {
classes()
.that().resideInAPackage("..service..")
.should().beAnnotatedWith(Service.class)
.check(importedClasses);
}
}
API ArchUnit Lang может определять правила для членов классов Java. Это может быть актуально, например, если методы в определенном контексте необходимо аннотировать с помощью определенной аннотации или если типы возвращаемых данных реализуют определенный интерфейс.Проверки уровней
class ArchunitApplicationTests {
private JavaClasses importedClasses;
@BeforeEach
public void setup() {
importedClasses = new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.springboot.testing.archunit");
}
@Test
void layeredArchitectureShouldBeRespected() {
layeredArchitecture()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
.layer("Repository").definedBy("..repository..")
.whereLayer("Controller").mayNotBeAccessedByAnyLayer()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
.whereLayer("Repository").mayOnlyBeAccessedByLayers("Service")
.check(importedClasses);
}
}
В приложении Spring Boot уровень сервиса зависит от уровня репозитория, уровень контроллера зависит от уровня сервиса.ArchUnit предлагает набор функций, проверяющих соблюдение вашей многоуровневой архитектуры. Эти тесты обеспечивают автоматические гарантии того, что доступ и использование поддерживаются в установленных вами пределах. Поэтому можно писать собственные правила. В этой статье мы описали несколько правил. Официальная докумуентация ArchUnit представляет значительно больше различных возможностей.Полный исходный код примеров можно найти в моем репозитории GitHub.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Anicet Eric
===========Похожие новости:
- [Тестирование IT-систем, Java, Apache] Apache Kafka и тестирование с Kafka Server
- [Java, API] Что было раньше: код или документация? OpenApi (OAS 3.0) и проблемы кодогенерации на Java
- [JavaScript, ReactJS] Все ли вы знаете о React key?
- [Java] Внедрение рекомендаций по структуре кода с использованием ArchUnit (перевод)
- [JavaScript] Namespaces в JavaScript
- [Разработка веб-сайтов, ReactJS] React — Используйте стандартные пропсы для потока данных
- [Информационная безопасность, Программирование, Java, GitHub, Софт] Архитектурные подходы к авторизации в серверных приложениях: Activity-Based Access Control Framework
- [Программирование, Java, Kotlin] Переезд из Java в Kotlin: как забрать коллекции с собой
- [Информационная безопасность, JavaScript, Google Chrome, Браузеры] Google Chrome начнет блокировать JavaScript-редирект по кликам на ссылки
- [Разработка веб-сайтов, JavaScript, Программирование] 20+ ES6-сниппетов для решения практических задач (перевод)
Теги для поиска: #_java, #_testing, #_best_practices, #_java
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:59
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
При создании программного обеспечения команды разработчиков обычно определяют набор руководящих принципов и соглашений по разработке кода, которые считаются лучшими практиками.Это методы, которые обычно документируются и доводятся до сведения всей команды разработчиков, которая их приняла. Однако во время разработки разработчики могут нарушить эти рекомендации, которые обнаруживаются во время ревью кода или с помощью инструментов проверки качества кода.Поэтому важным аспектом является автоматизация этих директив в максимально возможной степени по всей архитектуре проекта, позволяющая оптимизировать проверки.Мы можем реализовать эти рекомендации как проверяемые JUnit тесты с помощью ArchUnit. Это гарантирует, что сборка версии программного обеспечения будет прекращена в случае нарушения архитектуры. ArchUnit — это бесплатная, простая и расширяемая библиотека для проверки архитектуры вашего Java кода для использования в любой простой среде модульного тестирования Java. То есть ArchUnit может проверять зависимости между пакетами и классами, уровенями и срезами, проверять циклические зависимости и многое другое. Он делает это путем анализа данного байт-кода Java и импорта всех классов в структуру кода Java.
Примечание переводчика. Эта заметка дополняет предыдущую на тему ArchUnit.
<dependency>
<groupId>com.tngtech.archunit</groupId> <artifactId>archunit-junit5</artifactId> <version>0.14.1</version> <scope>test</scope> </dependency> dependencies {
testImplementation 'com.tngtech.archunit:archunit-junit5:0.14.1' } } class ArchunitApplicationTests {
private JavaClasses importedClasses; @BeforeEach public void setup() { importedClasses = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.springboot.testing.archunit"); } @Test void servicesAndRepositoriesShouldNotDependOnWebLayer() { noClasses() .that().resideInAnyPackage("com.springboot.testing.archunit.service..") .or().resideInAnyPackage("com.springboot.testing.archunit.repository..") .should() .dependOnClassesThat() .resideInAnyPackage("com.springboot.testing.archunit.controller..") .because("Services and repositories should not depend on web layer") .check(importedClasses); } } class ArchunitApplicationTests {
private JavaClasses importedClasses; @BeforeEach public void setup() { importedClasses = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.springboot.testing.archunit"); } @Test void serviceClassesShouldOnlyBeAccessedByController() { classes() .that().resideInAPackage("..service..") .should().onlyBeAccessed().byAnyPackage("..service..", "..controller..") .check(importedClasses); } } class ArchunitApplicationTests {
private JavaClasses importedClasses; @BeforeEach public void setup() { importedClasses = new ClassFileImporter() importedClasses = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.springboot.testing.archunit"); } @Test void serviceClassesShouldBeNamedXServiceOrXComponentOrXServiceImpl() { classes() .that().resideInAPackage("..service..") .should().haveSimpleNameEndingWith("Service") .orShould().haveSimpleNameEndingWith("ServiceImpl") .orShould().haveSimpleNameEndingWith("Component") .check(importedClasses); } @Test void repositoryClassesShouldBeNamedXRepository() { classes() .that().resideInAPackage("..repository..") .should().haveSimpleNameEndingWith("Repository") .check(importedClasses); } @Test void controllerClassesShouldBeNamedXController() { classes() .that().resideInAPackage("..controller..") .should().haveSimpleNameEndingWith("Controller") .check(importedClasses); } } class ArchunitApplicationTests {
private JavaClasses importedClasses; @BeforeEach public void setup() { importedClasses = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.springboot.testing.archunit"); } @Test void fieldInjectionNotUseAutowiredAnnotation() { noFields() .should().beAnnotatedWith(Autowired.class) .check(importedClasses); } @Test void repositoryClassesShouldHaveSpringRepositoryAnnotation() { classes() .that().resideInAPackage("..repository..") .should().beAnnotatedWith(Repository.class) .check(importedClasses); } @Test void serviceClassesShouldHaveSpringServiceAnnotation() { classes() .that().resideInAPackage("..service..") .should().beAnnotatedWith(Service.class) .check(importedClasses); } } class ArchunitApplicationTests {
private JavaClasses importedClasses; @BeforeEach public void setup() { importedClasses = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .importPackages("com.springboot.testing.archunit"); } @Test void layeredArchitectureShouldBeRespected() { layeredArchitecture() .layer("Controller").definedBy("..controller..") .layer("Service").definedBy("..service..") .layer("Repository").definedBy("..repository..") .whereLayer("Controller").mayNotBeAccessedByAnyLayer() .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller") .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service") .check(importedClasses); } } =========== Источник: habr.com =========== =========== Автор оригинала: Anicet Eric ===========Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:59
Часовой пояс: UTC + 5