ArchUnit 실천 : 집약 조작 전용의 리포지토리(나 DAO)에 의해서만, 집약이 영속화되는 것을 강제하는 ①<개별 ver.>
// 実行環境
* AdoptOpenJDK 11.0.9.1+1
* JUnit 5.7.0
* ArchUnit 0.14.1
아키텍처 테스트 동기 부여
집계를 구성하는 오브젝트는, 데이터베이스 등의 영속화층으로부터, 개별적으로 참조나 갱신하는 것이 아니라, 집약 루트를 기점으로서 집약(객체의 정합)으로서의 일관성을 유지하면서, 참조나 갱신하고 싶다.
아키텍처 테스트 구현
테스트 대상의 집계와 클래스의 샘플은 후술.
package com.example;
import com.example.domain.order.DenpyoAggregateDao;
import com.example.domain.order.DenpyoDao;
import com.example.domain.order.MeisaiDao;
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.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.theClass;
class ArchitectureTest {
// 検査対象のクラス
private static final JavaClasses CLASSES =
new ClassFileImporter()
.withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
.importPackages("com.example");
@ParameterizedTest
@ValueSource(classes = {
// 集約を構成する各エンティティに対応するDAO
DenpyoDao.class,
MeisaiDao.class
})
void 集約を構成する各エンティティに対応するDAOは集約操作専用のDAOによってのみ操作される(
final Class<?> daoClass
) {
// 集約操作専用のDAO
Class<DenpyoAggregateDao> aggregateDaoClass = DenpyoAggregateDao.class;
theClass(daoClass)
.should()
.onlyBeAccessed()
.byClassesThat()
.haveFullyQualifiedName(aggregateDaoClass.getName())
.check(CLASSES);
}
}
(참고) 테스트 대상 집계 샘플
다음과 같은 집계가 있다고 가정한다.
엔티티의 식별자를 나타내는 값 객체
public final class Identity<ENTITY> {
//...
}
문서 엔티티와 Dao
@Entity
public class Denpyo {
@Id
Identity<Denpyo> id;
@Transient
List<Meisai> meisaiList;
}
public interface DenpyoDao {
Optional<Denpyo> findById(Identity<Denpyo> id);
int insert(Denpyo denpyo);
int update(Denpyo denpyo);
}
품목 엔티티와 Dao
@Entity
public class Meisai {
@Id
Identity<Meisai> id;
Identity<Denpyo> denpyoId;
}
public interface MeisaiDao {
List<Meisai> findByDenpyoId(Identity<Denpyo> denpyoId);
int[] insert(List<Meisai> meisaiList);
int[] update(List<Meisai> meisaiList);
}
문서 및 품목을 집계로 조작하기 Aggregate Dao
public class DenpyoAggregateDao {
private final DenpyoDao denpyoDao;
private final MeisaiDao meisaiDao;
public DenpyoAggregateDao(final DenpyoDao denpyoDao, final MeisaiDao meisaiDao) {
this.denpyoDao = denpyoDao;
this.meisaiDao = meisaiDao;
}
// 集約の取得
Optional<Denpyo> findById(final Identity<Denpyo> id) {
return denpyoDao.findById(id).map(denpyo -> {
denpyo.meisaiList = meisaiDao.findByDenpyoId(denpyo.id);
return denpyo;
});
}
// 集約の登録
@Transactional
void insert(final Denpyo denpyo) {
assert denpyo.meisaiList != null;
denpyoDao.insert(denpyo);
// `伝票ID`がデータベース等により自動採番される場合はその値を`明細.伝票ID`に反映する
// denpyo.meisaiList.forEach(meisai -> meisai.denpyoId = denpyo.id);
meisaiDao.insert(denpyo.meisaiList);
}
// 集約の更新
@Transactional
void update(final Denpyo denpyo) {
assert denpyo.meisaiList != null;
denpyoDao.update(denpyo);
meisaiDao.update(denpyo.meisaiList);
}
}
Reference
이 문제에 관하여(ArchUnit 실천 : 집약 조작 전용의 리포지토리(나 DAO)에 의해서만, 집약이 영속화되는 것을 강제하는 ①<개별 ver.>), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/kawanamiyuu/items/62f52b09c74369e95551텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)