이 글은 인프런 스프링 프레임워크 핵심 기술을 보고 정리한 글입니다.
//의존 객체를 직접 만들어 사용하는 방법
BookRepository bookRepository = new BookRepository();
BookService bookService = new BookService(bookRepository);
//의존 객체를 직접 만들어 사용하는 방법
@Service
public class BookService {
private BookRepository bookRepository = new BookRepository();
}
//의존성 주입 방법 (생성자 주입 방식)
@Service
public class BookService {
private BookRepository bookRepository;//bookRepository는 빈으로 설정되있어야 함.
//생성자 주입 방식
//누군가 밖에서 주입해준다.
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
...
}
혹은
@Service
public class BookService {
//주입
@Autowired
private BookRepository bookRepository;
public void doSomething() {
// ....
}
}
등 여러 주입 방식이 있다.
IOC (Inversion of Control) 를 구현하는 프레임워크로 빈 설정 소스로부터 빈 정의를 읽어 빈을 구성하고 제공한다.
스프링 ioc 컨테이너의 가장 최상위 인터페이스, Ioc 컨테이너의 핵심
Bean의 생성과 설정, 관리를 맡고 있다.
BeanFactory를 상속받고 있기 때문에, BeanFactory와 같은 일을 한다고 볼 수 있다.
스프링 IoC 컨테이너가 관리 하는 객체.
//라이프사이클 인터페이스 예제
@Service
class BookService {
@PostConstruct
public void postConstruct() {
...
}
}
BookService는 bookRepository의 save가 null을 리턴하기 때문에 테스트를 할 수가 없다.
BookRepository를 구현해야지만 BookService를 테스트할 수 있다.
의존성의 문제 : 의존성을 가진 클래스들을 단위테스트 하기 힘들다(이 상황보다 BookService 클래스에서 BookRepository를 직접 생성하는 경우에는 더 힘들다.)
@Repository
public class BookRepository{
public Book save(Book book) {
return null;
}
}
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
public Book save(Book book) {
...
return bookRepository.save(book);
}
}
//테스트코드
public class BookServiceTest {
@Test
public void save() {
Book book = new Book();
BookRepository bookRepository = new BookRepository();
BookService bookService = new BookService(bookRepository);
Book result = bookService.save(book);
assertThat(book.getCreated()).isNotNull();
...
}
의존성 주입 방식 코드로 구현한 경우 얼마든지 가짜 객체를 만들어서 의존성 주입을 해주면 된다.
@RunWith(SpringRunner.class)
public class BookServiceTest {
@Mock
BookRepository bookRepository; // 가짜 객체
@Test
public void save() {
Book book = new Book();
when(bookRepository.save(book)).thenReturn(book); //save 메서드 호출시 book이 인자로 들어오면 book을 리턴하라
BookRepository bookRepository = new BookRepository();
BookService bookService = new BookService(bookRepository);
Book result = bookService.save(book);
assertThat(book.getCreated()).isNotNull();//book이라는 인스턴스가 들어왔기 때문에 테스트 동작됨
...
}