6.1 트랜잭션 코드의 분리
- 트랜잭션과 비지니스 로직이 서로 독립적인 코드일 때 비지니스 로직을 담당하는 코드를 메소드로 추출하기
- UserService클래스를 간접적으로 사용할 수 있도록 DI(클라이언트와의 결합 Down, 유연한 확장가능)
- UserServiceImpl - 비지니스 로직을 담고있음
- UserServiceTx - 트랜잭션 경계를 설정함.
- 사용 순서 : Client → UserServiceTx → UserService(UserServiceImpl DI)
- 트랜잭션과 비지니스 로직 분리로 인한 테스트 변경시 주의사항
- 테스트 수정 시 이름이 동일한 두개의 클래스 타입의 빈을 @Autowired로 가져올 경우 타입으로 검색 시 하나으 빈을 결정 할 수 없는 경우 필드이름을 사용해서 빈을 찾기 때문에 정확한 변수명 설정 필요.
- 목오브젝트를 이용해 수동으로 DI적용 시 클래스 오브젝트 명시 필요
- 트랜잭션 경계설정 코드 분리의 장점
- 비지니스 로직 수정 시 기술내용(ex.트랜잭션) 수정 X
- 비지니스 로직 테스트 용이
6.2 고립된 단위테스트
- 가장 좋은 테스트 방법은 가능한 작은 단위로 쪼개서 테스트 하는 것(테스트 실패 원인 찾기 쉬움)
- 테스트 대상이 다른 오브젝트와 환경에 의존하고 있다면 작은 단위 테스트의 장점을 얻기 어려움
- UserService테스트대상에 많은 오브젝트, 서버, 네트워크 등이 포함되므로 테스트의 대상이 환경이나 외부서버, 다른 클래스코드에 종속되고 영향받지 않도록 고립시킬 필요가 있다.
- 단위테스트
- 테스트 대상 클래스를 목 오브젝트 등의 테스트 대역을 이용해 의존 오브젝트나 외부의 리소스를 사용하지 않도록 고립시켜서 테스트
- 통합테스트
- 두개이상의 성격이나 계층이 다른 오브젝트가 연동하도록 만들거나 외부의 DB나 파일, 서비스등의 리소스가 참여하도록 하는 테스트
- 둘 중 어떤 테스트를 사용할까?
- 항상 단위 테스트를 먼저 고려
- 성격과 목적이 같은 긴밀한 클래스들을 모아 외부와의 의존관계 차단. 필요 시 테스트 대역을 이용
- 외부 리소스를 사용해야만 하는 테스트는 통합테스트 사용
- DAO는 DB를 통해 로직을 수행하는 인터페이스 같은 역할을 하므로 단위테스트 어려움 그러나 DAO를 이용하는 코드는 DAO역할을 스텁이나 목 오브젝트 프로젝트로 대체해서 테스트 가능
- 의존관계가 있을 시 통합테스트가 필요
- 단위테스트를 만들기 복잡한 코드는 통합테스트 고려(가능한 많은 부분을 단위테스트 하면 좋음)
- 스프링 테스트 컨텍스트 프레임워크를 이용하는 테스트는 통합테스트
- 목프레임워크 (대표적 Mockito)
- 목프레임워크를 일일히 준비할 필요 없음.
- Mockito의 스테틱 메소드 호출로 만들어짐
- 목오브젝트의 사용법
- 인터페이스를 이요해 목 오브젝트를 만들기
- 목오브젝트의 리턴값 존재 시 지정 필요
- 테스트 대상 오브젝트에 DI 해서 목오브젝트가 테스트 중에 사용되도록 만들기
- 목오브젝트의 특정 메소드 호출 여부와 호출 수, 어떤 값을 가지고 몇번 호출됐는지 검즈ㅡㅇ
6.3 다이내믹 프록시와 팩토리 빈
- 프록시 : 실제대상인것처럼 위장해서 클라이언트의 요청을 받아주는 대리인과 같은 역할