Spring

[Spring] 스프링 데이터 AbstractAggregateRoot 를 통해 도메인 이벤트 등록하고 테스트 하기

개발하는 지토 2021. 10. 31. 18:34

DDD 스터디중 구현해본 AbstractAggregateRoot를 통해 도메인 이벤트를 등록하고 테스트하는 방법을 간단하게만 정리함

(나중 참고용)

 

아직 깊은 지식이 없으므로 도메인 이벤트, AbstractAggregateRoot 에 대한 자세한 내용은 공식문서 & 타 블로그 정리 글을 참고하는 게 좋을 것 같음

 

https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/AbstractAggregateRoot.html

https://www.baeldung.com/spring-data-ddd

https://daddyprogrammer.org/post/14797/springboot-domainevent/


도메인 이벤트 등록

 

Entity가 AbstractAggregateRoot 를 상속하여 이벤트 등록이 가능하도록 함

 

@Entity
public class WishList extends AbstractAggregateRoot<WishList> {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long memberId;

    @OneToMany
    private final List<Lecture> lectures = new ArrayList<>();

    private boolean active;

... ...

}

 

 

AbstractAggregateRoot을 상속하면 registerEvent(T event) 메서드를 통해 간단히 이벤트를 등록 할 수 있음

 

// WishList 클래스의 add 메서드 : 위시 리스트에 강의를 추가하면 Cart(수강바구니)에서는 해당 강의를 삭제해주기 위한 이벤트 등록

public void add(Lecture lecture) {
    if (lectures.contains(lecture)) {
    throw new IllegalArgumentException("중복된 강의는 추가할 수 없다.");
    }
    
    lectures.add(lecture);
    
    log.info("publish CartInLectureRemovedEvent");
    registerEvent(new CartInLectureRemovedEvent(lecture, memberId));
}

 

 

EventListener에서는 단지 등록한 이벤트와 같은 타입의 클래스를 받아주기만 하면 이벤트 register - listen을 구현할 수 있음 (해당 클래스는 도메인 서비스로 정의함)

 

@Slf4j
@RequiredArgsConstructor
@DomainService
public class CartInLectureRemovedEventListener {

    private final CartRepository cartRepository;

    @Async
    @EventListener
    @Transactional
    public void listen(CartInLectureRemovedEvent cartInLectureRemovedEvent) {
        log.info("Listen CartInLectureRemovedEvent");
        Cart cart = cartRepository.findByMemberId(cartInLectureRemovedEvent.getMemberId());
        cart.removeByEvent(cartInLectureRemovedEvent.getLecture());
    }

}

 


이벤트 등록 테스트 작성 - 이게 맞는지 모르겠음,  좋은 방법이 있다면 알려주세용 :)

 

AbstractAggregateRoot를 상속한 엔티티 테스트 시 페이크 객체를 만들어서 테스트 진행

 

- class WishListTest

 

@DisplayName("강의를 추가시 수강바구니에서 해당 강의를 삭제하는 이벤트를 발행한다.")
@Test
public void publishEventByAddLecture() {
  // given
  FakeWishList wishList = WishListFixture.페이크_위시리스트();
  
  // when
  wishList.add(LectureFixture.승인_완료된_강의());

  // then
  assertThat(wishList.isRegist()).isTrue();
}

 

 

- class WishListFixture

 

public class WishListFixture {

    public static FakeWishList 페이크_위시리스트() {
        return new FakeWishList();
    }
}

 

 

- class FakeWishList

 

@Getter
public class FakeWishList extends WishList{
    private boolean regist;

    @Override
    protected <PublishedEvent> PublishedEvent registerEvent(PublishedEvent event) {
        this.regist = true;
        return super.registerEvent(event);
    }
}

 


결론: 도메인 이벤트를 통해 다른 애그리거트로 정의한 도메인과의 결합도를 낮춤

 

 

// 2021 10 31. -- 추 후에 발전 될 내용이 있으면 수정 필요