Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 혼자 공부하는 C언어
- coding test
- Selection Sorting
- datastructure
- stream
- Serialization
- JSON
- 윤성우의 열혈 자료구조
- R
- 이스케이프 문자
- C programming
- C 언어 코딩 도장
- Stack
- 알기쉬운 알고리즘
- s
- Graph
- list 컬렉션
- buffer
- Algorithm
- 메모리구조
- 이것이 자바다
- insertion sort
- 윤성우 열혈자료구조
Archives
- Today
- Total
Engineering Note
[Spring] 의존성 주입(DI)과 테스트의 관계 본문
1. 의존성 주입이란?
의존성 주입(Dependency Injection, DI)은 객체가 사용할 다른 객체를 직접 생성하지 않고, 외부에서 주입받는 방식을 말합니다.
스프링에서는 컨테이너(ApplicationContext)가 객체를 Bean으로 관리하고, 필요한 곳에 자동으로 주입해주기 때문에 @Autowired나 생성자 주입을 통해 쉽게 DI를 구현할 수 있습니다.
2. 왜 필요한가? (순수 자바 관점)
순수 자바에서 보자면, 클래스가 의존 객체를 직접 생성하는 경우 테스트와 유지보수가 어렵습니다.
의존성을 직접 생성하는 경우
class A {
private B b = new B(); // A가 B를 직접 생성
public void doSomething() {
b.work();
}
}
- A는 항상 B라는 구체 클래스에 묶여 있습니다.
- B를 C로 교체하거나, 테스트에서 Mock 객체를 사용하고 싶어도 불가능합니다.
의존성을 주입받는 경우
class A {
private final B b;
public A(B b) { // 생성자 주입
this.b = b;
}
public void doSomething() {
b.work();
}
}
- 이제 A는 “나에게 B가 필요하다”라는 의존성만 선언합니다.
- 실제 어떤 객체를 넣을지는 외부에서 결정합니다.
B b = new B();
A a = new A(b); // 외부에서 주입
3. 테스트 관점에서의 장점
테스트할 때 진짜 B 대신 MockB를 주입할 수 있습니다.
class MockB extends B {
@Override
public void work() {
System.out.println("Mock 동작");
}
}
@Test
void testA() {
B mockB = new MockB(); // 진짜 대신 Mock
A a = new A(mockB);
a.doSomething(); // "Mock 동작" 검증 가능
}
이렇게 하면 A의 로직만 검증할 수 있고, B의 실제 동작에 의존하지 않아 단위 테스트가 깔끔해집니다.
→ 유연한 설계 + 테스트 용이성 확보
3-1. 필드 주입의 문제점
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
}
- 불변성 없음
: private 필드인데도 리플렉션을 통해 주입되므로, 테스트나 리팩토링 과정에서 실수로 값이 바뀔 수 있음. - 테스트 어려움
: 단위 테스트 시 new OrderService()로 직접 객체 생성하면 orderRepository가 null → 직접 주입 불가. - 숨겨진 의존성
: 생성자를 보면 어떤 객체가 필요한지 알 수 없음. 코드를 열어봐야 함. - 순환 참조 감지 불가
: 필드 주입은 순환 참조 발생 시 런타임에만 에러가 납니다.
3-2. 생성자 주입의 장점
@Service
public class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
}
- 불변성 확보
: final 키워드로 의존성을 변경 불가능하게 유지. Java 에서 final이 붙은 필드는 선언과 동시에 초기화를 하거나 생성자를 통해 반드시 초기화를 해야한다. - 테스트 용이
: 스프링 컨테이너 없이도
new OrderService(new FakeOrderRepository());
- 이런 식으로 테스트 가능.
- 의존성 명시적 표현
: 생성자에 파라미터로 다 드러나므로 “이 서비스가 무엇을 필요로 하는지” 명확히 알 수 있음. - 순환 참조 조기 감지
: 스프링이 애플리케이션 실행 시점에 바로 순환 참조 에러를 알려줌.
3-3. 스프링 공식 권장
스프링 팀도 공식 문서, 강의, 코드 컨벤션에서 생성자 주입을 기본으로 삼고 있다.
4. 결론
- DI는 단순히 스프링의 기능이 아니라 객체지향 설계 원칙(DIP)을 지키기 위한 방법입니다.
- 생성자 주입을 사용하면 테스트에서 Mock 객체를 쉽게 넣을 수 있고, 코드 결합도를 낮출 수 있습니다.
- 따라서 스프링 진영에서는 “생성자 주입 권장”이라는 가이드가 자연스럽게 따라옵니다.
'Server > Spring' 카테고리의 다른 글
[Spring] Spring Boot 프로젝트 생성시 사용 되는 개념 (0) | 2025.10.08 |
---|---|
[Spring] @Transactional 어노테이션과 Spring AOP의 관계 (0) | 2025.10.07 |
[Spring] Static Resource 경로 설정하기 (0) | 2025.09.15 |
[Spring] @RequestParam (0) | 2025.09.15 |
[Spring] @PathVariable, @RequestParam (0) | 2025.08.24 |
Comments