[Java] Модульное тестирование архитектуры Spring Boot проекта с помощью ArchUnit (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
12-Ноя-2020 19:32

При создании программного обеспечения команды разработчиков обычно определяют набор руководящих принципов и соглашений по разработке кода, которые считаются лучшими практиками.Это методы, которые обычно документируются и доводятся до сведения всей команды разработчиков, которая их приняла. Однако во время разработки разработчики могут нарушить эти рекомендации, которые обнаруживаются во время ревью кода или с помощью инструментов проверки качества кода.Поэтому важным аспектом является автоматизация этих директив в максимально возможной степени по всей архитектуре проекта, позволяющая оптимизировать проверки.Мы можем реализовать эти рекомендации как проверяемые 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
===========
Похожие новости: Теги для поиска: #_java, #_testing, #_best_practices, #_java
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 20:59
Часовой пояс: UTC + 5