본문 바로가기

web +a

생성자 주입 권장

수정자 주입 문제점

: setter를 public으로 열어두는 것은 변경의 소지가 있음 => 좋지 않은 설계임

: 프레임워크 도움 없이 순수하게 자바코드로 단위테스트 할 경우 

 

생성자 주입 권장

: 대부분 한번 의존관계를 주입하면 애플리케이션 종료때까지 변경할 일이 없고, 불변해야 함

: 생성자는 객체생성시 딱 1번만 호출하므로 불변 설계 가능

: final 키워드를 사용할 수 있다.

  생성자에서만 세팅 가능 & 반드시 세팅하게 됨 & 한번 정해지면 불변

 

 

필드 주입은 사용하지 말자

: 코드는 엄청 간단하지만.. 그냥 앞에 @Autowired를 붙이면 끝이지만.. 

: 스프링 컨테이너 없이는 Test 아예 불가

: 딱딱해짐

 

 


(예시)

수정자 메서드를 둘 경우 Test에서 자주 만나게 될 문제

(순수 자바 코드 & 스프링기능X)

 

orderService 인스턴스를 사용하려면 orderService 인스턴스와 의존관계가 있는 필드에 값을 할당해주어야 하는데 수정자 주입이기 때문에 저렇게만 해서는 필드인 memberRepository와 discountPolicy에 아무 것도 들어 있지 않게 되어 NPE가 일어난다. 

테스트 코드에서는 OrderServiceImpl 객체와 다른 객체의 의존관계가 보이지 않는다. OrderServiceImpl 코드를 열어봐야 알 수 있다. 그래서 수정자 주입일 경우 의존관계에 대한 문제 때문에 테스트가 원활하지 않다.

class OrderServiceImpleTest {
    @Test
    void createOrder() {
        OrderServiceImpl orderService = new OrderServiceImpl();
        orderService.createOrder(1L, "itemA", 10000);
    }
}

 

그러나 생성자 주입인 경우 의존관계 주입을 누락하지 않고 테스트 가능하다. 

class OrderServiceImpleTest {
    @Test
    void createOrder() {
        OrderServiceImpl orderService = new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
        orderService.createOrder(1L, "itemA", 10000);
    }
}

 

참고) orderService.createOrder()메서드는 필드 memberRepository가 1L이 id인 Member객체를 갖고 있어야 해서 아래와 같이 사용한다. 즉 id가 1L인 회원의 가입이 선행되었어야 한다. 

    @Test
    void createOrder() {
        MemoryMemberRepository memberRepository = new MemoryMemberRepository();
        memberRepository.save(new Member(1L, "name", Grade.VIP));

        OrderServiceImpl orderService = new OrderServiceImpl(memberRepository, new FixDiscountPolicy());
        Order order = orderService.createOrder(1L, "itemA", 10000);

        org.assertj.core.api.Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
    }


 

 

 

반응형
다른 블로그