의존성 주입(DI)의 3가지 유형
DI의 주요 유형
- 생성자 주입(Constructor Injection) : 의존성을 생성자를 통해 주입받는 방식
- 일반 생성자를 이용한 주입
1
2
3
4
5
6
7
8
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
...
}
2. Lombok의 @AllArgsConstructor 사용
1
2
3
4
5
@AllArgsConstructor
public class UserService {
private final UserRepository userRepository;
...
}
- 세터 주입(Setter Injection) : 의존성을 세터 메서드를 통해 주입받는 방식
1
2
3
4
5
6
7
8
public class UserService {
private UserRepository userRepository;
// 세터를 통한 주입
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
- 필드 주입(Field Injection) : 의존성을 필드에 직접 주입하는 방식
1
2
3
4
5
public class UserService {
@Autowired
private UserRepository userRepository;
}
결론
테스트 환경
생성자 주입(Constructor Injection)
장점
- 테스트 용이성: 객체를 생성할 때 모든 필수 의존성을 명시적으로 전달받기 때문에, 테스트 시 의존성을 쉽게 모의 객체(Mock)로 교체할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11
public class UserServiceTest { @Test public void testUserService() { // Mock 객체 생성 UserRepository mockRepository = Mockito.mock(UserRepository.class); // 생성자 주입을 통해 의존성 주입 UserService userService = new UserService(mockRepository); ... } }
- 불변성: 의존성이 생성자를 통해 한 번 설정되면 변경되지 않기 때문에 객체의 상태를 안정적으로 유지할 수 있습니다.
단점
- 코드 길이: 필드가 많은 클래스의 경우 생성자 파라미터가 길어질 수 있어 코드가 복잡해질 수 있습니다.
- 테스트 용이성: 객체를 생성할 때 모든 필수 의존성을 명시적으로 전달받기 때문에, 테스트 시 의존성을 쉽게 모의 객체(Mock)로 교체할 수 있습니다.
세터 주입(Setter Injection)
장점
- 유연성: 런타임 시점에 의존성을 동적으로 변경할 수 있어 특정 테스트 케이스에 필요한 의존성만 주입할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12
public class UserServiceTest { @Test public void testUserService() { // Mock 객체 생성 UserRepository mockRepository = Mockito.mock(UserRepository.class); // Setter 주입을 통해 의존성 주입 UserService userService = new UserService(); userService.setUserRepository(mockRepository); ... } }
- 선택적 의존성: 필요에 따라 의존성이 없는 상태로 객체를 생성할 수 있어 테스트가 용이합니다.
단점
의존성 누락: 객체 생성 후에 의존성을 설정하지 않을 경우 NullPointerException과 같은 예외가 발생할 수 있습니다.
객체의 상태 변경: 의존성이 외부에서 변경될 수 있어 객체의 상태를 예측하기 어려울 수 있습니다.
- 유연성: 런타임 시점에 의존성을 동적으로 변경할 수 있어 특정 테스트 케이스에 필요한 의존성만 주입할 수 있습니다.
필드 주입(Field Injection)
장점
- 간결한 코드: 필드 주입은 코드가 간결하고 직관적입니다. 별도의 생성자나 세터 메서드를 작성할 필요가 없어 테스트 코드 작성이 편리합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public class UserServiceTest { @Mock private UserRepository mockRepository; @InjectMocks private UserService userService; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testUserService() { ... } }
단점
- 테스트 어려움: 필드 주입을 사용할 경우, 테스트에서 의존성을 목 객체로 교체하기 어려울 수 있습니다. 이로 인해 테스트가 실제 데이터베이스나 외부 서비스에 의존해야 할 때 문제가 발생할 수 있습니다.
- 간결한 코드: 필드 주입은 코드가 간결하고 직관적입니다. 별도의 생성자나 세터 메서드를 작성할 필요가 없어 테스트 코드 작성이 편리합니다.
어떤 DI 유형을 선택해야 할까?
생성자 주입: 필수적인 의존성이 있는 경우나 불변성을 유지해야 할 때 좋은 선택입니다.
세터 주입: 선택적인 의존성이 필요한 경우나, 기본 생성자를 사용할 때 유용합니다.
필드 주입: 간단한 프로토타입 코드나 테스트용 코드에서 사용할 수 있지만, 일반적인 애플리케이션 코드에서는 지양하는 것이 좋습니다.
This post is licensed under CC BY 4.0 by the author.