ArchUnit:輕松測試軟件架構(gòu)

為什么要測試你的架構(gòu)?

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

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

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

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

什么是 ArchUnit

ArchUnit 用于單元測試 Java 項目架構(gòu)翠忠。它可以檢查包和類、層和切片之間的依賴關系乞榨,檢查循環(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 測試類。

這可以通過以下方式輕松實現(xiàn):

@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");
        }
    }

}

結(jié)論

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

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

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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末咱台,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子俭驮,更是在濱河造成了極大的恐慌回溺,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件表鳍,死亡現(xiàn)場離奇詭異馅而,居然都是意外死亡,警方通過查閱死者的電腦和手機譬圣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門瓮恭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人厘熟,你說我怎么就攤上這事屯蹦∥” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵登澜,是天一觀的道長阔挠。 經(jīng)常有香客問我,道長脑蠕,這世上最難降的妖魔是什么购撼? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谴仙,結(jié)果婚禮上迂求,老公的妹妹穿的比我還像新娘。我一直安慰自己晃跺,他們只是感情好揩局,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著掀虎,像睡著了一般凌盯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上烹玉,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天驰怎,我揣著相機與錄音,去河邊找鬼春霍。 笑死砸西,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的址儒。 我是一名探鬼主播芹枷,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莲趣!你這毒婦竟也來了鸳慈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤喧伞,失蹤者是張志新(化名)和其女友劉穎走芋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體潘鲫,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡翁逞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溉仑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挖函。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浊竟,靈堂內(nèi)的尸體忽然破棺而出怨喘,到底是詐尸還是另有隱情津畸,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布必怜,位于F島的核電站肉拓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏梳庆。R本人自食惡果不足惜暖途,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望靠益。 院中可真熱鬧丧肴,春花似錦残揉、人聲如沸胧后。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壳快。三九已至,卻和暖如春镇草,著一層夾襖步出監(jiān)牢的瞬間眶痰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工梯啤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留竖伯,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓因宇,卻偏偏與公主長得像七婴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子察滑,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容