⌨️ 인프런 워밍업 클럽 2기 미션 Day-18
이번 미션은 @Mock, @MockBean, @Spy, @SpyBean @InjectMock의 차이점과 주어진 테스트 상황의 구조를 수정하는 미션 두 가지이다. 먼저 Test Double에 대해서 정리를 하도록 하겠다.
1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMock의 차이
1.1 Test Double과 각 Annotation의 차이
https://www.martinfowler.com/bliki/TestDouble.html
마틴 파울러의 Article이다.
우선 @Mock 과 @Spy는 테스트 더블의 범주이며 @InjectMock은 그 카테고리가 아예 다르다.
Annotation답게 그 이름 자체로도 유추할 수 있으며,
@Mock과 @Spy는 Mock객체와 Spy객체를 만드는 데 들어가는 일련의 보일러-플레이트 과정을 축약한 것이다.
거기에 단순히 Spring에서 활용하기 위해 그 뒤에 Bean을 덧붙혀 그 의도를 나눈 것이다 즉
@MockBean과 @SpyBean은 Spring Test 환경에서만 동작한다.
보다시피 Spring 테스트가 아닌 환경에서 @MockBean을 사용하자 NPE가 뜬다
@InjectMock은 @Mock 객체를 주입받을 객체를 지정해주기 위해 사용한다.
Spring 환경에서는 @MockBean은 테스트를 하고 싶은 객체에 Spring Container에 의해 알아서 주입된다.
2. 테스트 재배치
아래와 같은 테스트를 본인의 생각을 반영하여 재배치 해야한다.
@BeforeEach
void setUp() {
❓
}
@DisplayName("사용자가 댓글을 작성할 수 있다.")
@Test
void writeComment() {
1-1. 사용자 생성에 필요한 내용 준비
1-2. 사용자 생성
1-3. 게시물 생성에 필요한 내용 준비
1-4. 게시물 생성
1-5. 댓글 생성에 필요한 내용 준비
1-6. 댓글 생성
// given
❓
// when
❓
// then
검증
}
@DisplayName("사용자가 댓글을 수정할 수 있다.")
@Test
void updateComment() {
2-1. 사용자 생성에 필요한 내용 준비
2-2. 사용자 생성
2-3. 게시물 생성에 필요한 내용 준비
2-4. 게시물 생성
2-5. 댓글 생성에 필요한 내용 준비
2-6. 댓글 생성
2-7. 댓글 수정
// given
❓
// when
❓
// then
검증
}
@DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.")
@Test
void cannotUpdateCommentWhenUserIsNotWriter() {
3-1. 사용자1 생성에 필요한 내용 준비
3-2. 사용자1 생성
3-3. 사용자2 생성에 필요한 내용 준비
3-4. 사용자2 생성
3-5. 사용자1의 게시물 생성에 필요한 내용 준비
3-6. 사용자1의 게시물 생성
3-7. 사용자1의 댓글 생성에 필요한 내용 준비
3-8. 사용자1의 댓글 생성
3-9. 사용자2가 사용자1의 댓글 수정 시도
// given
❓
// when
❓
// then
검증
}
우선 재배치하고 나의 생각을 정리토록 하겠다
@BeforeEach
void setUp() {
1-1. 사용자 생성에 필요한 내용 준비
1-2. 사용자 생성
1-3. 게시물 생성에 필요한 내용 준비
1-4. 게시물 생성
2-1. 사용자 생성에 필요한 내용 준비
2-2. 사용자 생성
2-3. 게시물 생성에 필요한 내용 준비
2-4. 게시물 생성
3-1. 사용자1 생성에 필요한 내용 준비
3-2. 사용자1 생성
3-5. 사용자1의 게시물 생성에 필요한 내용 준비
3-6. 사용자1의 게시물 생성
// 사용자1과 사용자가 같은 객체 즉 setUp에서 사용자와 사용자의 게시물만 생성
}
@DisplayName("사용자가 댓글을 작성할 수 있다.")
@Test
void writeComment() {
// given
1-5. 댓글 생성에 필요한 내용 준비
// when
1-6. 댓글 생성
// then
검증
}
@DisplayName("사용자가 댓글을 수정할 수 있다.")
@Test
void updateComment() {
// given
2-5. 댓글 생성에 필요한 내용 준비
2-6. 댓글 생성
// when
2-7. 댓글 수정
// then
검증
}
@DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.")
@Test
void cannotUpdateCommentWhenUserIsNotWriter() {
// given
3-7. 사용자1의 댓글 생성에 필요한 내용 준비
3-8. 사용자1의 댓글 생성
3-3. 사용자2 생성에 필요한 내용 준비
3-4. 사용자2 생성
// when
3-9. 사용자2가 사용자1의 댓글 수정 시도
// then
검증
}
나는 위와 같이 재배치 할 것 같다.
2.1. 이유
SetUp에는 세 테스트에서 모두 공통적으로 사용되는 사용자와 게시물 한 개를 생성할 것 같다.
그리고 이 두 객체는 이 테스트에서 검증할 요소가 아니므로 직관적으로 보이지 않아도 된다고 생각했다.
위와 같은 관점에서 세 테스트에 모두 사용자의 댓글 생성에 필요한 준비와 댓글 생성이 있지만
SetUp하지 않은 이유는 이 테스트에서 직접적으로 검증할 요소이기에 Given에 직관적으로 보여야 한다고 생각했기 때문이다.
또한 사용자2는 테스트3에만 필요하므로 1,2에서 SetUp할 필요는 없다고 생각해 3의 Given으로 주었다.
뭔가 되게 심플..? 그냥 좀 가볍게 생각하고 접근한 것이라 나중에 다른 분들의 의견을 보고 시야를 넓혀야겠다.