inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1

회원 애플리케이션 기능 추가

테스트 준비 과정에서 서비스 메서드 호출

188

dlwogns3413

작성한 질문수 19

0

@Test
void find() {
    Member member = memberRegister.register(MemberFixture.createMemberRegisterRequest());
    entityManager.flush();
    entityManager.clear();

    Member found = memberFinder.find(member.getId());

    assertThat(member.getId()).isEqualTo(found.getId());
}

현재 코드에서 위와 같이 테스트에서 회원 저장을 위해 memberRegister.register를 호출하고 있습니다.

그런데 memberRegister.register에는 단순히 회원을 저장하는 것 외에도 이메일 전송 같은 부가적인 로직이 포함되어 있습니다. 이러한 부가적인 로직때문에 테스트 속도가 느려진다던가, 테스트가 실패하는 원인이 될 수 있다고 생각이 들었습니다.

이처럼 테스트 준비에 필요하지 않은 부가 로직까지 수행되는 상황에서, memberRegister.register를 테스트 준비 용도로 사용하는 것이 적절한지 토비님의 생각이 궁금합니다.

java spring spring-boot jpa 리팩터링 ddd

답변 1

1

토비

좋은 지적이십니다. 회원 가입 뿐 아니라 서비스, API 수준의 테스트를 하게 되면 DB와 내부 로직 적용 외에 외부 서비스 호출 등이 포함될 수 있습니다. 메일, SMS, 카톡 메시지 전송, 심지어는 은행 계좌 이체를 위한 API 실행 등도 들어갈 수도 있겠죠. 이러면 테스트 실행 성능도 떨어지고, 심지어 위험할 수 있습니다. 테스트용 이메일 발송으로 인해 이메일 전송 서비스 비용이 많이 나올 수도 있겠죠.

이런 것들이 헥사고날 아키텍처를 사용하는 이유의 하나 입니다.

애플리케이션 테스트를 외부 환경에 독립적으로 가능하게 하는 것이죠.

아직 이메일 발송 기능을 정식으로 구현하지 않았습니다(Part 2에서는 실제 메일이 발송되도로 구현할 겁니다). 그렇지만 메일 발송 기능이 있다고 하더라도 테스트에서는 이게 실행되지 않도록 해야 합니다. 메일 전송과 같은 헥사곤 외부에 요청할 기능은 required interface로 정의해두고요. EmailSender 인터페이스로 만들었죠. 그리고 테스트용 스프링 설정에 이 구현을 넣습니다. 그러면 메인 코드에서 실제 이메일이 발송되도록 구현한 코드가 있더라도, 그걸 무시하고 테스트쪽에 넣은 일종의 mock/stub 오브젝트에 해당하는 스프링 빈 코드가 실행됩니다.

제가 코드를 찾아보니 SplearnTestConfiguration 클래스로 만들어졌네요.

@TestConfiguration
public class    SplearnTestConfiguration {
    @Bean
    public EmailSender emailSender() {
        return (email, subject, body) -> System.out.println("Sending email: " + email);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return MemberFixture.createPasswordEncoder();
    }
}

이렇게 테스트가 실행될 때는 외부 기능이 운영 환경과 다르게 동작하도록 재구성하는 방법을 사용하면 됩니다. 그러면 순수하게 회원 가입 기능을 담당하는 코드와 DB(테스트용 메모리 DB)에 대한 테스트를 빠르게 진행할 수 있습니다.

그래서 마지막 질문에 대한 답은 테스트에서 실행될 필요가 없는 외부 기능은 테스트용 목 오브젝트를 사용하면 되기 때문에 MemberRegister.register()는 테스트 만들고 매번 실행하는데 아무 문제가 없습니다.

N+1 관련해서 질문있습니다.

0

46

3

도메인 모델에서 관계와 규칙을 구분하는 방법

0

61

2

헥사고날 아키텍처에서의 배치, 시큐리티, 비동기 이벤트 처리는 어떻게 하나요?

0

140

2

어댑터에서 도메인에 직접 의존하는 경우에 대해

0

136

2

Member 도메인이 PasswordEncoder를 받는 구조 질문 있습니다.

0

118

2

MemberService와 EmailSender 책임 분리에 대한 질문

0

111

2

NonNullApi를 NullMarked로 대체하라고 합니다.

0

133

2

39. 문서와 코드 다듬기 updateInfo 테스트 질문 있습니다.

0

82

2

Repository Adapter 설계에 대해 피드백을 부탁드립니다

0

112

2

헥사고날 part2 강의 출시 예정일 문의 드립니다.

0

264

2

PT 문의사항

0

104

1

초기 어플리케이션 구동 시 compose.yml 파싱 오류

0

154

2

애플리케이션의 JPA 리턴과 도메인 모델

0

131

2

애그리거트 루트의 하위 도메인들의 depth가 깊어질 때 문의

0

140

2

페이징 처리를 해야한다면 어떻게 해야할까요?

0

198

2

애그리거트의 repository

0

128

2

Domain Expert가 정확히 어떤 역할을 하는 사람인가요?

0

240

1

회원 애플리케이션 서비스 테스트 (1)

0

110

2

정적 팩토리 메서드 관련 질문드립니다!

0

112

2

spotbug + @NonNullApi 로만 Null 방어가 될까요?

0

132

2

required 포트에 관해서

0

96

2

혹시 다음 편은 언제쯤 오픈할까요?

0

173

2

서비스 단위 테스트 코드 작성

0

104

2

domain 모듈에 entity를 정의한다고 했을때

0

106

2