ArchUnit:輕松測試軟件架構

為什么要測試你的架構?

當項目變得更大,架構變得更加復雜。每個項目都有開發(fā)人員需要遵循的標準規(guī)則。
新開發(fā)人員加入,他們可能會在不知情的情況下違反架構約束。如果每個人都在他們認為合適的地方添加新代碼,每一個變化都可能對任何其他組件產生不可預見的影響,代碼庫就會變得混亂。

當然,您可以讓一名或多名經驗豐富的開發(fā)人員擔任架構師的角色,他們每周查看一次代碼,找出違規(guī)行為并加以糾正。

問題是這需要人工干預,有時我們并不能發(fā)現所有問題。保護軟件架構免遭破壞的最佳方式是采用自動化流程。

在本文中,我將展示解決此類問題的 ArchUnit 框架。您將看到典型的實際示例,以了解如何將此工具集成到您的項目中。

什么是 ArchUnit

ArchUnit 用于單元測試 Java 項目架構。它可以檢查包和類、層和切片之間的依賴關系,檢查循環(huán)依賴關系等等。通常,開發(fā)人員會建立通用模式。
當有人違反規(guī)則時,測試將失敗。開發(fā)人員將看到有關該問題的信息。它確保代碼庫保持完整,并且每個人都遵循準則。

ArchUnit 演示

我們創(chuàng)建一個 Spring Boot 項目,將 ArchUnit maven 依賴項添加到您的pom.xml:

<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit</artifactId>
    <version>1.0.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>com.tngtech.archunit</groupId>
    <artifactId>archunit-junit5</artifactId>
    <version>1.0.1</version>
    <scope>test</scope>
</dependency>

我們創(chuàng)建一個 ArchUnitTest.java 的Java類,我們將把所有的測試都放在那里。

命名檢查測試

如果您有多個模塊,您可以使用注釋 @AnalyzeClasses 指出要掃描的包:

@AnalyzeClasses(packages = "com.relive")

例如,您可能希望 SpringBoot 項目中 Application 類名稱應為“SpringBootTestApplication”:

@ArchTest
    public static final ArchRule application_class_name_should_be =
            classes().that().areAnnotatedWith(SpringBootApplication.class)
                    .should().haveSimpleName("SpringBootTestApplication");

您可以檢查是否所有 Controller 類都具有后綴“Controller”:

@ArchTest
    static ArchRule controllers_suffixed_should_be =
            classes().that().resideInAPackage("..controller..")
                    .or().areAnnotatedWith(RestController.class)
                    .should().haveSimpleNameEndingWith("Controller")
                    .allowEmptyShould(true);

包位置測試

您可能想檢查實體類是否位于“entity”包中:

@ArchTest
    static final ArchRule tablename_must_reside_in_a_entity_package =
            classes().that().areAnnotatedWith(TableName.class)
                    .should().resideInAPackage("..entity..")
                    .as("TableName should reside in a package '..entity..'")
                    .allowEmptyShould(true);

同樣,您可以檢查配置類是否位于“config”包中:

@ArchTest
    static final ArchRule configs_must_reside_in_a_config_package =
            classes().that().areAnnotatedWith(Configuration.class)
                    .or().areNotNestedClasses()
                    .and().areAnnotatedWith(ConfigurationProperties.class)
                    .should().resideInAPackage("..config..")
                    .as("Configs should reside in a package '..config..'")
                    .allowEmptyShould(true);

注釋測試

所有配置類都應具有 @Configuration 或者 @ConfigurationProperties 其中之一:

    @ArchTest
    static ArchRule configs_should_be_annotated =
            classes()
                    .that().resideInAPackage("..config..")
                    .and().areNotNestedClasses()
                    .should().beAnnotatedWith(Configuration.class)
                    .orShould().beAnnotatedWith(ConfigurationProperties.class);

圖層測試

所有 Service 層的 Java 類僅可以被 Controller 層訪問,Dao 層的 Java 類僅可以被 Service 層訪問:

@ArchTest
    static ArchRule layer_inspection = layeredArchitecture()
            .consideringAllDependencies()
            .layer("Controller").definedBy("..controller..")
            .layer("Service").definedBy("..service..")
            .layer("Dao").definedBy("..dao..")

            .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
            .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
            .whereLayer("Dao").mayOnlyBeAccessedByLayers("Service");

測試排除

有時某些類我們不想執(zhí)行規(guī)則,例如 JUnit 測試類。

這可以通過以下方式輕松實現:

@AnalyzeClasses(packages = "com.relive", importOptions = {ImportOption.DoNotIncludeTests.class})

或者有一個你想忽略的類,因為規(guī)則不適用于它。我們可以創(chuàng)建一個自定義規(guī)則并導入它,如下所示:

@AnalyzeClasses(packages = "com.relive", importOptions = {ArchUnitTest.ExcludeControllerImportOption.class})
public class ArchUnitTest {


    static class ExcludeControllerImportOption implements ImportOption {
        @Override
        public boolean includes(Location location) {
            return !location.contains("SomeExcludedControllerClasses");
        }
    }

}

結論

現在你已經了解如何將 ArchUnit 測試框架集成到您的 Java 項目中。您還熟悉了一些應用中的常用規(guī)則。

如果你想了解更多關于 ArchUnit 的規(guī)則示例,你可以參考 ArchUnit 用戶指南
我想這里可以讓你更加深入研究。

與往常一樣,本文中使用的源代碼可在 GitHub 上獲得。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容