📝
go言語ArchUnitっぽいテストコードを作った
依存関係をUTで制御する良さそうなライブラリがなかったので、サクッと自作(AI作)したのでメモ。
import (
"fmt"
"golang.org/x/tools/go/packages"
"strings"
"testing"
)
type DependencyRule struct {
Package string // パッケージ名
ShouldNotDepend []string // 禁止される依存パッケージのリスト
}
func CollectDependencies(rules []DependencyRule) []error {
var response []error
cfg := &packages.Config{Mode: packages.NeedImports | packages.NeedDeps | packages.NeedName}
// パッケージ全体の情報を取得
pkgs, err := packages.Load(cfg, "./...")
if err != nil {
panic(err)
}
for _, pkg := range pkgs {
for _, rule := range rules {
targetMatch := strings.HasPrefix(pkg.PkgPath, rule.Package)
// ルールにマッチしない場合はスキップ
if !targetMatch {
continue
}
for _, forbidden := range rule.ShouldNotDepend {
for importPackage := range pkg.Imports {
importMatch := strings.HasPrefix(importPackage, forbidden)
if importMatch {
response = append(response, fmt.Errorf("package %s depends on forbidden package %s", pkg.PkgPath, importPackage))
}
}
}
}
}
return response
}
func TestDependencyRules(t *testing.T) {
// 規定のパッケージを指定
prefix := "your-app/components/internal/"
// 依存関係のルールを定義
rules := []DependencyRule{
// application層はadapter層に依存してはいけない
{Package: prefix + "application", ShouldNotDepend: []string{
prefix + "adapter",
}},
// domain層はadapter層, application層に依存してはいけない
{Package: prefix + "domain", ShouldNotDepend: []string{
prefix + "adapter",
prefix + "application",
}},
}
errors := CollectDependencies(rules)
if len(errors) > 0 {
var msg string
for _, validate := range errors {
msg += fmt.Sprintf("%v\n", validate)
}
t.Errorf("Dependency rule violated: \n%s", msg)
}
}
Discussion