// 実行環境
* 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);
}
}