TypescriptでArchUnitしてみた
ArchUnit をというものを最近知りました。依存関係のテストができるそうです。さっそく試してみたいと思いますので、その備忘録として残しておきます。
ArchUnit
ArchUnit is a free, simple and extensible library for checking the architecture of your Java code using any plain Java unit test framework. That is, ArchUnit can check dependencies between packages and classes, layers and slices, check for cyclic dependencies and more. It does so by analyzing given Java bytecode, importing all classes into a Java code structure.
Java のアーキテクチャをテストできるライブラリで、パッケージやクラス、レイヤー、スライス(?)の依存関係をテストできるそうです。 そこで、親の顔よりも見たこの図をテストしたいと思います。
Typescript でも ArchUnit したい
ArchUnit は Java 製です。私は Typescript の ArchUnit がしたいです。 そこで、良さげなライブラリを発見しました。
https://github.com/MaibornWolff/ts-arch
特に拘りなく、アーキテクチャのテストができれば何でも良いかなと思います。 極端な話、ソースコードを AST パースし、依存関係を抽出できれば自作できるんじゃないかと思います。
試してみた
試したソースコードは、下記に置いています。ご参考下さい。
https://github.com/silverbirder/try-archunit
全体のソースコードツリーは次の構成です。
src
└ 1_enterprise_business_rules
└ entities
└ Entity.ts
└ 2_application_business_rules
└ use_cases
└ UseCase.ts
└ 3_interface_adapters
└ controllers
└ Controller.ts
└ gateways
└ Gateway.ts
└ presenters
└ Presenter.ts
└ 4_frameworks_and_drivers
└ web
└ Web.ts
└ clean_architecture.puml
└ clean_architecture.test.ts
各プロダクトコードは、下の階層のファイルを import しているだけとします。
// src/4_frameworks_and_drivers/web/Web.ts
import "../../3_interface_adapters/gateways/Gateway";
import "../../3_interface_adapters/controllers/Controller";
import "../../3_interface_adapters/presenters/Presenter";
// src/3_interface_adapters/controllers/Controller.ts
import "../../2_application_business_rules/use_cases/UseCase";
// src/2_application_business_rules/use_cases/UseCase.ts
import "../../1_enterprise_business_rules/entities/Entity";
// src/1_enterprise_business_rules/entities/Entity.ts
下記ファイルにある UML のコンポーネント図で依存関係を表します。
# clean_architecture.puml
@startuml
component [4_frameworks_and_drivers] #Blue
component [3_interface_adapters] #Green
component [2_application_business_rules] #Red
component [1_enterprise_business_rules] #Yellow
4_frameworks_and_drivers --> 3_interface_adapters
3_interface_adapters --> 2_application_business_rules
2_application_business_rules --> 1_enterprise_business_rules
@enduml
UML を可視化すると、下記の図のとおりです。
テストコードは、下記のとおりです。
// clean_architecture.test.ts
describe("architecture", () => {
it("Check dependency", async () => {
const architectureUml = path.resolve(__dirname, "clean_architecture.puml");
const violations = await slicesOfProject()
.definedBy("src/(**)/")
.should()
.adhereToDiagramInFile(architectureUml)
.check();
await expect(violations).toEqual([]);
});
});
このテストケースは PASS します。
では、違反コードを書いてみます。
// src/3_interface_adapters/controllers/Controller.ts
import "../../2_application_business_rules/use_cases/UseCase";
import "../../4_frameworks_and_drivers/web/Web";
3 レイヤーが上位の 4 レイヤーを使用しています。この状態でテストを実行すると、
見事 Failed となりました。つまり、依存関係の誤りを自動的に検出することができます。
最後に
規模が大きなプロジェクトほど、依存関係が複雑になりがちです。(Java でいう) パッケージやクラスの依存関係を適切に設計できていたとしても、誰かが壊しかねません。せっかく設計したのに壊されるのは、とても残念なので、テストコードで守ってあげましょう!
シェアしよう
関連するタグ
- Docker Image に 構造化テスト container-structure-test を試してみた
- Testcontainersを用いたNext.jsとDBの結合テスト
- Million Lintを試してみた
- Playwright Component Test を試してみた
- Typescript で Document Testing したい
- Storybook上で tRPC通信をMSWでモックする方法
- CucumberとScreenplay設計によるE2Eテスト
- Webフロントエンドにおける網羅的テストパターンガイド
- BigQueryだけで完結するモック可能なユニットテスト手法
- Webアプリのテスト観点を調べてまとめてみた (25選)
- Google Apps Script でも テスト がしたい! (Clasp + Typescript + Jest)
- ユニットテストを書く上で守りたいこと
- CircleCI + BackstopJS (Puppeteer) でビジュアルリグレッションテストを継続的に監視する