생성자 주입이 권장되는 이유를 나름대로 정리해보기
생성자 주입 및 필드 주입
현장 주입의 장점과 단점
장점
@Autowired
를 붙이는 것만이므로 인젝트 하는 것이 편하다. @Autowired
를 붙이는 것만으로 끝난다. 단점
필드 인젝션에서의 구현 예
@Service
public class BookService{
@Autowired
private BookDao bookDao;
@Autowired
private HogeDao hogeDao;
/**
* 引数のbookIdと一致したBookを返す
*/
public Book selectById(int bookId){
Optional<Book> wrappedBook = bookDao.findById(bookId);
return wrappedBook.orElseThrow(() -> NotFoundException("無い"));
}
.
.
.
}
생성자 주입의 장점과 단점
장점
단점
생성자 주입에서의 구현 예
@Service
public class BookService{
private final BookDao bookDao;
private final HogeDao hogeDao;
@Autowired // → Spring4.3以上ならこのアノテーション省略可
public BookService(BookDao bookDao, HogeDao hogeDao){
this.bookDao = bookdao;
this.hogeDao = hogedao;
}
/**
* 引数のbookIdと一致したBookを返す
*/
public Book selectById(int bookId){
Optional<Book> wrappedBook = bookDao.findById(bookId);
return wrappedBook.orElseThrow(() -> NotFoundException("無い"));
}
.
.
.
}
생성자 주입으로 테스터빌리티 향상
필드 인젝션으로 구현된 클래스를 테스트하는 경우
@Autowired
로 인젝트 된 필드는 SpringBoot 가 제공하고 있는 @MockBean
를 사용하는 것으로 모의 수 있습니다. @ExtendWith(SpringExtension.class)
와 @SpringBootTest
가 필요합니다. @ExtendWith(SpringExtension.class)
@SpringBootTest
public class BookServiceTests{
@Autowired
private BookService bookService;
@MockBean
private BookDao bookDao;
@MockBean
private HogeDao hogeDao;
@Test
public void 指定したbookIdの本を取得できること(){
// setUp
var expected = new Book(1, "本の名前");
when(bookDao.findById(1)).thenReturn(expected);
var bookService = new BookService();
// execute
var actual = bookService.selectById(1);
// verify
assertThat(...以下省略
}
}
@MockBean
를 붙이는 것만으로 끝나기 때문에 매우 편하게 보입니다만 SpringBootTest는 유닛 테스트에 비해서 꽤 시간이 걸립니다.... Failed to create application context
라는 오류가 발생합니다. (경험 완료)@Table
로 테이블이 없는 경우는 자동 생성하는 구현으로 하고 있는 것이 원인...? 생성자 주입으로 구현된 클래스를 테스트하는 경우
@BeforeEach
메소드로 mock 할 필요가 있는 것이 조금 번거로울지도 모릅니다. @ExtendWith(SpringExtension.class)
와 @SpringBootTest
가 필수적이었지만 여기에서는 붙일 필요가 없습니다.
public class BookServiceTests{
private BookService bookService;
private BookDao bookDao;
private HogeDao hogeDao;
@BeforeEach
public void setUp(){
bookDao = Mockito.mock(BookDao.class);
hogeDao = Mockito.mock(HogeDao.class);
bookService = new BookService(bookDao, hogeDao);
}
@Test
public void 指定したbookIdの本を取得できること(){
// setUp
var expected = new Book(1, "本の名前");
when(bookDao.findById(1)).thenReturn(expected);
var bookService = new BookService();
// execute
var actual = bookService.selectById(1);
// verify
assertThat(...以下省略
}
}
Failed to create application context
이나 「DB가...」라고 하는 에러도 괴롭히는 일이 없어져, 스트레스 없이 테스트를 할 수 있습니다 @BeforeEach
를 붙인 메소드로 스스로 mock 하는 것이 귀찮은 경우는 Mockito가 제공하고 있는 @Mock
를 부여하는 것으로 간단하게 mock 할 수 있습니다. public class BookServiceTests{
private BookService bookService;
@Mock
private BookDao bookDao;
@Mock
private HogeDao hogeDao;
@BeforeEach
public void setUp(){
bookService = new BookService(bookDao, hogeDao);
}
// 以下省略
@RunWith(MockitoJUnitRunner.class)
가 필요하게 되는 것입니다. 참고
Reference
이 문제에 관하여(생성자 주입이 권장되는 이유를 나름대로 정리해보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/kmuro/items/aead50c699fefe56c120텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)