ArchUnit 実践:集約操作専用のリポジトリ(やDAO)によってのみ、集約が永続化されることを強制する②<汎用 ver.>


// 実行環境
* AdoptOpenJDK 11.0.9.1+1
* JUnit 5.7.0
* ArchUnit 0.14.1

アーキテクチャテストのモチベーション

21 日目の ArchUnit 実践:集約操作専用のリポジトリ(やDAO)によってのみ、集約が永続化されることを強制する① は特定の集約とその Dao クラス対して実装ルールを強制するアーキテクチャテストでした。
今回は実現したいことはそのままに、特定の Dao クラス名や AggregateDao クラス名をハードコードせず、汎用的なアーキテクチャテストとして実装します。

アーキテクチャテストの実装

package com.example;
 
import com.tngtech.archunit.base.DescribedPredicate;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.core.importer.ImportOption;
import org.junit.jupiter.api.Test;

import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;

class ArchitectureTest {

    // 検査対象のクラス
    private static final JavaClasses CLASSES =
            new ClassFileImporter()
                    .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
                    .importPackages("com.example");

    @Test
    void AggregateDaoから使用されるDaoは他のクラスから使用されない() {
        classes().that()
            .haveSimpleNameEndingWith("Dao")
            .and(new DescribedPredicate<>("are injected into AggregateDao") {
                @Override
                public boolean apply(final JavaClass daoClass) {
                    // "AggregateDao から使用される Dao" を、
                    // "AggregateDao に対してコンストラクタ・インジェクションされる Dao" と、
                    // 解釈してみる。

                    Set<JavaConstructor> constructorsThatDaoClassIsInjectedInto =
                        daoClass.getConstructorsWithParameterTypeOfSelf();

                    return constructorsThatDaoClassIsInjectedInto.stream()
                        .map(JavaMember::getOwner)
                        .anyMatch(clazz -> clazz.getSimpleName().endsWith("AggregateDao"));
                }
            })
            .should()
            .onlyBeAccessed()
                .byClassesThat()
                .haveSimpleNameEndingWith("AggregateDao")
            .check(CLASSES);
    }
}