0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アーキテクチャテストAdvent Calendar 2020

Day 3

ArchUnit 実践:パッケージの依存関係のアーキテクチャテスト

Last updated at Posted at 2020-12-03
// 実行環境
* AdoptOpenJDK 11.0.9.1+1
* JUnit 5.7.0
* ArchUnit 0.14.1

2日目の ArchUnit 実践:依存関係を逆転した Layered Architecture のアーキテクチャテスト を、別のテスト構文を用いて実装します。

例①: UI 層のクラスはインフラストラクチャ層のクラスからのみ依存される

image.png

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

package com.example;

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;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

class ArchitectureTest {

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

    @Test
    void UI層のクラスはインフラストラクチャ層のクラスからのみ依存される() {
        classes().that().resideInAPackage("com.example.presentation..")
                .should()
                .onlyHaveDependentClassesThat().resideInAPackage(
                    "com.example.infrastructure.."
                )
                .check(CLASSES);
    }
}

アーキテクチャテストの実行例(テスト失敗例)

1日目の ArchUnit 実践:Layered Architecture のアーキテクチャテスト の失敗原因と同じく、アプリケーション層の Service クラスが、プレゼンテーション層の Helper クラスに依存してしまっている、というアーキテクチャ違反を検知した想定でのテスト失敗例。

$ ./gradlew clean check

> Task :test

ArchitectureTest > UI層のクラスはインフラストラクチャ層のクラスからのみ依存される() FAILED
    java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'classes that reside in a package 'com.example.presentation..' should only have dependent classes that reside in a package 'com.example.infrastructure..'' was violated (2 times):
    Constructor <com.example.application.employee.EmployeeRegisterService.<init>(com.example.presentation.JsonRenderHelper)> has parameter of type <com.example.presentation.JsonRenderHelper> in (EmployeeRegisterService.java:0)
    Field <com.example.application.employee.EmployeeRegisterService.jsonRenderHelper> has type <com.example.presentation.JsonRenderHelper> in (EmployeeRegisterService.java:0)
        at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94)
        at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:82)
        at com.tngtech.archunit.lang.ArchRule$Factory$SimpleArchRule.check(ArchRule.java:198)
        at com.tngtech.archunit.lang.syntax.ObjectsShouldInternal.check(ObjectsShouldInternal.java:81)
        at com.example.ArchitectureTest.UI層のクラスはインフラストラクチャ層のクラスからのみ依存される(ArchitectureTest.java:54)

2 tests completed, 1 failed

例②:ドメイン層のクラスは他の層のクラスに依存しない

image.png

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

package com.example;

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;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;

class ArchitectureTest {

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

    @Test
    void ドメイン層のクラスは他の層のクラスに依存しない() {
        noClasses().that().resideInAPackage("com.example.domain..")
            .should()
            .dependOnClassesThat().resideInAnyPackage(
                "com.example.presentation..",
                "com.example.application..",
                "com.example.infrastructure.."
            )
            .check(CLASSES);
    }
}

アーキテクチャテストの実行例(テスト失敗例)

2日目の ArchUnit 実践:依存関係を逆転した Layered Architecture のアーキテクチャテスト の失敗原因と同じく、ドメイン層の Service クラスが、インフラストラクチャ層の Repository クラスに依存してしまっている、というアーキテクチャ違反を検知した想定でのテスト失敗例。

$ ./gradlew clean check

> Task :test FAILED

ArchitectureTest > ドメイン層のクラスは他の層のクラスに依存しない() FAILED
    java.lang.AssertionError: Architecture Violation [Priority: MEDIUM] - Rule 'no classes that reside in a package 'com.example.domain..' should depend on classes that reside in any package ['com.example.presentation..', 'com.example.application..', 'com.example.infrastructure..']' was violated (2 times):
    Constructor <com.example.domain.employee.EmployeeService.<init>(com.example.infrastructure.datasource.EmployeeRepository)> has parameter of type <com.example.infrastructure.datasource.EmployeeRepository> in (EmployeeService.java:0)
    Field <com.example.domain.employee.EmployeeService.employeeRepository> has type <com.example.infrastructure.datasource.EmployeeRepository> in (EmployeeService.java:0)
        at com.tngtech.archunit.lang.ArchRule$Assertions.assertNoViolation(ArchRule.java:94)
        at com.tngtech.archunit.lang.ArchRule$Assertions.check(ArchRule.java:82)
        at com.tngtech.archunit.lang.ArchRule$Factory$SimpleArchRule.check(ArchRule.java:198)
        at com.tngtech.archunit.lang.syntax.ObjectsShouldInternal.check(ObjectsShouldInternal.java:81)
        at com.example.ArchitectureTest.ドメイン層のクラスは他の層のクラスに依存しない(ArchitectureTest.java:99)

2 tests completed, 1 failed
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?