1. IoC (Inversion of Control) : 제어의 역전
- IoC는 코드의 의존성을 외부에서 관리하여 복잡성과 오류를 줄이며 테스트를 용이하게 함
- IoC를 설명하기 위해 아래의 예제 코드를 사용(Book, BookService, BookRepository, BookStatus)
// Book.class
package org.springframework.samples.petclinic.book;
import java.util.Date;
public class Book {
private Date created;
private BookStatus bookStatus;
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public BookStatus getBookStatus() {
return bookStatus;
}
public void setBookStatus(BookStatus bookStatus) {
this.bookStatus = bookStatus;
}
}
// BookRepository.class
package org.springframework.samples.petclinic.book;
import org.springframework.stereotype.Repository;
@Repository
public class BookRepository {
public Book save(Book book){
return null;
}
}
// BookService.class
package org.springframework.samples.petclinic.book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class BookService {
@Autowired // BookRepository는 의존성 주입을 받고있음
// 이 코드는 BookRepository와 BookService간의 의존관계를 나타내고 있음
private BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public Book save(Book book){
book.setCreated(new Date());
book.setBookStatus(BookStatus.DRAFT);
return bookRepository.save(book);
}
}
// BookStatus.class
package org.springframework.samples.petclinic.book;
public enum BookStatus {
DRAFT, PUBLISHED;
}
- IoC 미적용 코드(내가 사용할 의존성은 내가 만들어서 사용)
// BookService.class
package org.springframework.samples.petclinic.book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
public class BookService {
BookRepository bookRepository = new BookRepository(); // BookRepository를 직접 인스턴스화
public BookService(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
public Book save(Book book){
book.setCreated(new Date());
book.setBookStatus(BookStatus.DRAFT);
return bookRepository.save(book);
}
}
- IoC 적용 코드(내가 사용할 의존성을 외부에서 누군가가 주입해줌, 의존성의 타입만 맞으면 어떤거든 상관없음)
// BookService.class
package org.springframework.samples.petclinic.book;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
public class BookService {
@Autowired // BookRepository는 의존성 주입을 받고있음
private BookRepository bookRepository;
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
} // 이 코드는 BookRepository와 BookService간의 의존관계를 나타내고 있음
public Book save(Book book){
book.setCreated(new Date());
book.setBookStatus(BookStatus.DRAFT);
return bookRepository.save(book);
}
}
- BookServiceTest (IoC 미적용 코드 테스트)
public class BookServiceTest {
private BookRepository bookRepository;
@Test
public void save(){
Book book = new Book();
BookRepository bookRepository = new BookRepository();
BookService bookService = new BookService(bookRepository);
Book result = bookService.save(book);
//bookRepository의 return 값이 null이기 때문에 아래의 코드는 에러를 발생시킨다.
assertThat(book.getCreated()).isNotNull();
assertThat(book.getBookStatus()).isEqualTo(BookStatus.DRAFT);
assertThat(result).isNotNull();
}
위의 "테스트 코드는 에러 코드"를 유발한다. bookService.save(book)의 Return 값이 현재 Null로 되어있기 때문에 해당 코드가 asserThat 코드에서 기대하는 결과값을 뱉어내게끔 동작 테스트를 하고자 한다면 직접 BookService.class 내의 코드를 변경해주어야 한다.
- BookServiceTest (IoC 적용 코드 테스트)
package org.springframework.samples.petclinic.book;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
@RunWith(SpringRunner.class)
public class BookServiceTest {
@Mock // Mock 객체 생성 (Mock은 일종의 가짜 객체이다.)
private BookRepository bookRepository;
@Test
public void save(){
Book book = new Book();
when(bookRepository.save(book)).thenReturn(book); // 목킹작업, save(book)이 들어오면 book을 리턴해라
// RunWith 어노테이션을 사용하지 않으면 Mock이 발생되지 않음 -> NullPointException 발생
BookService bookService = new BookService(bookRepository);
Book result = bookService.save(book);
assertThat(book.getCreated()).isNotNull();
assertThat(book.getBookStatus()).isEqualTo(BookStatus.DRAFT);
assertThat(result).isNotNull();
}
}
위와 같은 단위 테스트 수행시 IoC 컨테이너에서 관리되는 Bean 객체를 Mock이라는 가짜 Bean 객체로 주입받은뒤 when 기능을 이용하여 특정 값을 리턴하도록 테스트 시나리오를 작성하고 assertThat으로 결과값에 대한 검증이 가능하다.
'4. Backend Development > 1. Spring Framework' 카테고리의 다른 글
6. DispatcherServlet (0) | 2020.09.01 |
---|---|
5. Servlet (0) | 2020.09.01 |
4. MacOS Security Management System (0) | 2020.07.21 |
3. Spring Framework 기반 웹 프로젝트 (0) | 2020.06.09 |
2. Spring IoC Container (0) | 2020.04.30 |
댓글