
워밍업 클럽 3기 BE 클린코드&테스트 - Day18 미션
@Mock
목적: 객체를 단순히 Mocking하여 테스트에서 사용할 수 있도록 합니다.
사용 범위: Spring 컨텍스트와 무관한 일반적인 단위 테스트에 사용됩니다.
특징:
실제 구현체를 대체하는 Mock 객체를 생성합니다.
Spring 컨텍스트를 로드하지 않으며 독립적인 테스트 환경에서 사용됩니다.
사용 시점: 단일 클래스와 메서드의 동작을 격리하여 테스트할 때 적합합니다
예시:
@Mock
private Dependency dependency;
@InjectMocks
private SomeService someService;
@MockBean
목적: Spring 컨텍스트 내의 Bean을 Mock으로 대체하거나 새로 추가합니다.
사용 범위: 통합 테스트에서 사용되며 Spring 컨텍스트를 로드하는 경우에 적합합니다.
특징:
Spring 애플리케이션 컨텍스트에 Mock 객체를 추가하거나 기존 Bean을 대체합니다.
Spring Boot의
@SpringBootTest
와 함께 사용됩니다.사용 시점: Spring 컨텍스트가 필요한 통합 테스트에서 특정 Bean을 Mock으로 대체할 때 적합합니다
예시:
@SpringBootTest
public class SomeServiceIntegrationTest {
@MockBean
private Dependency dependency;
@Autowired
private SomeService someService;
}
@Spy
목적: 객체를 Spy로 생성하여 일부 메서드는 실제 구현을 호출하고, 일부는 Mocking할 수 있도록 합니다.
사용 범위: 일반적인 단위 테스트에서 사용됩니다.
특징:
객체의 실제 구현을 유지하면서 특정 메서드만 Mocking하거나 검증할 수 있습니다.
독립적인 테스트 환경에서 사용됩니다.
사용 시점: 객체의 일부 동작은 실제로 실행하며 특정 메서드만 Mocking해야 할 때 적합합니다.
예시:
// 서비스 로직
public boolean sendMail(String fromEmail, String toEmail, String subject, String contents) {
boolean result = mailSendClient.sendMail(fromEmail, toEmail, subject, contents);
if (result) {
mailSendHistoryRepository.save(MailSendHistory.builder()
.fromEmail(fromEmail)
.toEmail(toEmail)
.subject(subject)
.contents(contents)
.build()
);
mailSendClient.a();
mailSendClient.b();
mailSendClient.c();
return true;
}
return false;
}
// 테스트 코드
@Spy
private MailSendClient mailSendClient;
@DisplayName("메일 전송 테스트")
@Test
void sendMail() {
// given (mailSendClient.sendMail의 sendMail만 Mocking)
doReturn(true)
.when(mailSendClient)
.sendMail(anyString(), anyString(), anyString(), anyString());
}
@SpyBean
목적: Spring 컨텍스트 내의 Bean을 Spy로 대체하거나 추가합니다.
사용 범위: 통합 테스트에서 사용되며 Spring 컨텍스트를 로드하는 경우에 적합합니다.
특징:
Spring 애플리케이션 컨텍스트 내의 기존 Bean을 Spy로 감싸거나 새로 추가합니다.
SpyBean은 모든 메서드가 기본적으로 실제 구현을 호출하지만 특정 메서드는 Mocking할 수 있습니다.
사용 시점: Spring 컨텍스트 내에서 Bean의 동작을 검증하거나 일부 메서드를 변경해야 할 때 적합합니다.
예시:
@SpringBootTest
public class MyServiceTest {
@SpyBean
private MyDependency myDependency;
@Autowired
private MyService myService;
}
@InjectMocks
목적:
@Mock
또는@Spy
로 생성된 Mock 객체를 테스트 대상 클래스에 주입합니다.사용 범위: 단위 테스트에서 사용됩니다.
특징:
생성자 주입, 세터 주입, 필드 주입 방식으로 Mock 객체를 자동으로 주입합니다.
테스트 대상 클래스 인스턴스를 생성하고 필요한 의존성을 주입합니다.
사용 시점: 여러 의존성을 가진 클래스를 테스트할 때, 해당 의존성을 자동으로 주입해야 할 경우 적합합니다.
예시:
@Mock
private Dependency dependency;
@InjectMocks
private SomeService someService;
// dependency가 자동으로 someService에 주입됩니다.
@BeforeEach, given절, when절 적절한 배치
@BeforeEach
void setUp() {
1-1, 2-1. 사용자 생성에 필요한 내용 준비
1-2, 2-2. 사용자 생성
1-3, 2-3. 게시물 생성에 필요한 내용 준비
1-4, 2-4. 게시물 생성
}
@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-1. 사용자1 생성에 필요한 내용 준비
3-2. 사용자1 생성
3-3. 사용자2 생성에 필요한 내용 준비
3-4. 사용자2 생성
3-5. 사용자1의 게시물 생성에 필요한 내용 준비
3-6. 사용자1의 게시물 생성
3-7. 사용자1의 댓글 생성에 필요한 내용 준비
3-8. 사용자1의 댓글 생성
// when
3-9. 사용자2가 사용자1의 댓글 수정 시도
// then
검증
}
댓글을 작성해보세요.