워밍업 클럽 3기 BE 클린코드&테스트 - Day18 미션

워밍업 클럽 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
    검증
}

댓글을 작성해보세요.

채널톡 아이콘