5.4 메일 서비스의 추상화
5.4.0 새로운 요구사항 접수 새로운 요구사항 새로운 요구사항 실현을 위한 변경 사항 레벨이 업그레이드 되는 사용자에게 안내 메일 발송 새로운 요구사항 실현을 위한 변경 사항 사용자 이메일 정보 관리 User에 email 필드 추가 UserDao 수정 userMapper 수정 insert(), update()에 email 필드 처리 코드 추가 UserServiceTest, UserDaoTest, UserTest 수정 업그레이드 작업을 담은 UserService의 upgradeLevel() 메소드에 메일 발송 기능 추가
5.4.1 JavaMail을 이용한 메일 발송 기능 JavaMail 메일 발송 upgradeLevel() 메소드 수정
5.4.1 JavaMail을 이용한 메일 발송 기능 JavaMail 메일 발송 javax.mail.JavaMail 클래스 사용 sendUpgradeEmail() 메소드 추가
5.4.2 JavaMail이 포함된 코드의 테스트 개발 중 JavaMail 관련 테스트시 고려점 개발 중 메일 서버가 부재한(올바르지 않은) 경우의 테스트 실패 개발 중 메일 서버가 올바르게 동작한다고 해도 매번 메일을 보내는 것이 올바른가? 테스트 실행은 빈번하게 발생 그 때 마다 메일 발송은 서버에 많은 부담 테스트시 수신자의 메일 주소는 올바른가? 괜찮은 해결책: 테스트용 메일 서버를 별도로 준비하여 사용
5.4.2 JavaMail이 포함된 코드의 테스트 개발 중 JavaMail 관련 테스트시 고려점 장점 매번 검증이 필요 없는 불필요한 메일 전송 요청을 보내지 않아도 됨 테스트가 빠르고 안전하게 수행됨
5.4.3 테스트를 위한 서비스 추상화 JavaMail을 이용한 테스트의 문제점 JavaMail의 핵심 클래스: javax.mail.Session Session 클래스의 경직성 Session은 인터페이스가 아니고 클래스 생성자가 private이라 직접 객체 생성 불가능 스태틱 팩토리 메소드를 이용하여 객체 Session 클래스는 상속이 불가능한 final 클래스 MailMessage와 Transport 클래스도 마찬가지임 JavaMail의 구현을 테스트용으로 바꿔치기가 거의 불가능
5.4.3 테스트를 위한 서비스 추상화 스프링의 JavaMail 추상화 스프링의 JavaMail 관련 클래스 및 코드 스프링은 java가 제공하는 JavaMail을 사용해 만든 코드가 테스트에 용이치 않은점을 인지하고 별도로 추상화 기능을 제공하고 있음 스프링의 JavaMail 관련 클래스 및 코드 MailSender/MailMessage 인터페이스 SimpleMailMessage 클래스
5.4.3 테스트를 위한 서비스 추상화 스프링의 JavaMail 관련 클래스 및 코드 JavaMailSender 인터페이스와 JavaMailSenderImpl 클래스 지저분한 try/catch 블록이 사라짐 MailException 런타임 예외 사용
5.4.3 테스트를 위한 서비스 추상화 스프링의 JavaMail 관련 클래스 및 코드 스프링의 DI 적용
5.4.3 테스트를 위한 서비스 추상화 스프링의 JavaMail 관련 클래스 및 코드 설정 파일 내의 빈 등록 현재까지는 기존 Java에서 제공하는 JavaMail API에서 스프링의 JavaMail API를 사용하도록 변경 메일 전송 기능을 인터페이스를 사용하여 추상화 DI를 통한 구체적 클래스 완전 분리 테스트에 활용하기가 매우 용이
5.4.3 테스트를 위한 서비스 추상화 테스트용 메일 발송 객체 테스트용 MailSender 클래스인 DummyMailSender 구현 send() 메소드가 실제로 하는 일이 없음 콘솔에 메일 내용을 출력하는 정도로 업그레이드 가능
5.4.3 테스트를 위한 서비스 추상화 테스트용 메일 발송 객체 DummyMailSender 빈 등록 UserServerTest 클래스에 테스트시 구현한 upgradeAllOrNothing() 메소드에도 mailSender 빈을 수동으로 주입
5.4.3 테스트를 위한 서비스 추상화 테스트와 서비스 추상화 서비스 추상화 기능은 유사하나 사용 방법이 다른 로우레벨의 다양한 기술에 대해 추상 인터페이스와 일관성 있는 접근 방법을 제공해 주는 것 스프링의 JavaMail 서비스 추상화 사용 JavaMail 의 구체적 기능이 변경되어도 클라이언트인 UserService는 전혀 수정할 필요가 없음
5.4.4 테스트 대역 의존 객체의 변경을 통한 테스트 방법 UserDaoTest는 UserDao의 동작을 테스트하기 위함 테스트시에는 SimpleDataSource를 사용하여 실제 운영하여 서버 활용을 못하게 막음 그럼에도 불구하고, 다음과 같은 단점 존재 테스트 DB와의 연결 SimpleDataSource 빈 생성 및 UserDao로의 DI 작업 UserDao 테스트만을 목적으로 한다면 위의 간단한 작업들 모두 번거로운 짐이 됨
5.4.4 테스트 대역 의존 객체의 변경을 통한 테스트 방법 UserServiceTest는 UserService의 동작을 테스트하기 위함 테스트시에는 DummyMailServer를 사용하여 실제 메일 전송차단 이 경우 그 외 번거로운 작업은 없음
5.4.4 테스트 대역 테스트 대상 객체의 의존성 문제 테스트 대역 (Test Double) UserService: 테스트 대상 객체 UserService는 DI를 통해 주입받는 객체가 세가지임 즉, UserService는 이 세가지 객체에 의존적이 됨 문제점 간단하게 UserService만을 테스트하기 위하여 DI를 통하여 세가지 객체를 주입하는 거창한 작업이 뒤따름 테스트 대역 (Test Double) 테스트 대상 객체가 사용하는 의존 객체들을 대체할 수 있도록 만든 객체 즉, 테스트 대상 객체가 원활하게 동작할 수 있도록 도우면서 테스트를 위해 간접적인 정보를 제공해주기도 함 종류: 테스트 스텁 (Test Stub)과 목 객체 (Mock Object)
5.4.4 테스트 대역 테스트 스텁 (Test Stub) 테스트 대상 객체의 의존객체로서 존재하면서 테스트 동안에 코드가 정상적으로 수행할 수 있도록 돕는 객체 테스트 코드 내부에서만 간접적으로 사용 테스트시에 DI를 통하여 테스트 대상 객체에 주입함 예: DummyMailSender 테스트 스텁의 한계 테스트 대상 객체의 메소드가 돌려주는 결과뿐 아니라 의존 객체가 넘기는 값과 그 행위 자체에 대한 검증이 불가함
5.4.4 테스트 대역 목 객체 (Mock Object) 테스트 대상 객체와 의존 객체 사이에서 일어나는 일을 검증할 수 있도록 특별히 설계된 객체 테스트 스텁처럼 테스트 객체가 정상적으로 실행되도록 도와주면서 테스트 객체와 자신 사이에서 일어나는 내용을 저장해 두었다가 테스트 결과를 검증하는 데 활용할 수 있도록 도와줌 (1)~(4)까지는 테스트 스텁과 동일한 기능 (5): 목 객체는 테스트 대상 객체와 자신 사이에 주고받는 정보를 보존하고 테스트에게 직접 그 정보를 제공한다.
5.4.4 테스트 대역 목 객체를 이용한 테스트 upgradeLevels() 테스트의 확장 메일 전송이 실제로 되었다는 점을 어느 정도 확인할 수 있도록 확장 send() 메소드가 수행되면 수신자의 메일 주소를 저장 외부에서는 접근자 메소드 getRequest()를 통해 저장해둔 메일 주소 확인 가능
5.4.4 테스트 대역 목 객체를 이용한 테스트 목 객체는 테스트 대상 객체의 내부에서 일어나는 일이나 자신과 함께 일어나는 일들에 대해 검증하게 해줌