Mockito, Mock 과 Spy

조원준·2022년 8월 4일
0

도입

아래와 같은 예시 코드가 있다.

@ExtendWith(MockitoExtension.class)
public class UnitTest {

	TestConfig.MemberCreator memberCreator = new TestConfig.MemberCreator(
        new TestConfig.MemberValidator(),
        new TestConfig.EmailSender()
    );

    @Test
    @DisplayName("멤버를 생성해 보자")
    public void createMember() {
        // given
        Long id = 1L;
        String name = "꿣꿣꿣";

        // when
        Long result = memberCreator.create(id, name);

        // then
        assertThat(result).isEqualTo(id);
    }

    public static class TestConfig {
        public static class MemberCreator {

            private final MemberValidator memberValidator;
            private final EmailSender emailSender;

            public MemberCreator(MemberValidator memberValidator, EmailSender emailSender) {
                this.memberValidator = memberValidator;
                this.emailSender = emailSender;
            }

            public Long create(Long id, String name) {
                memberValidator.validate(id, name);
                emailSender.sendEmail(name);
                System.out.println("id = " + id);
                System.out.println("name = " + name);
                memberCreateSuccessMessage();
                return id;
            }

            public void memberCreateSuccessMessage() {
                System.out.println("멤버 생셩됨");
            }
        }

        public static class MemberValidator {
            public void validate(Long id, String name) {
                throw new RuntimeException("무조건 실패시킬꺼");
            }
        }

        public static class EmailSender {
            public void sendEmail(String name) {
                System.out.println(name + " 에게 이메일 발송됨");
            }
        }
    }
}

테스트는 "무조건 실패시킬꺼" 에러를 빵빵 터뜨린다.
이 테스트를 성공시키기 위해서는 MemberCreator 에 의존하고 있는 Validator 와 EmailSender 를 Mocking 처리해야 한다.

@ExtendWith(MockitoExtension.class)
public class UnitTest {

	@Mock
    TestConfig.MemberValidator memberValidator;

    @Mock
    TestConfig.EmailSender emailSender;

    @InjectMocks
    TestConfig.MemberCreator memberCreator;
    

    @Test
    @DisplayName("멤버를 생성해 보자")
    public void createMember() {
        // given
        Long id = 1L;
        String name = "꿣꿣꿣";

        // when
        Long result = memberCreator.create(id, name);

        // then
        assertThat(result).isEqualTo(id);
    }
    ... 중략
    
}

테스트는 성공하게 된다.

[결과]
id = 1
name = 꿣꿣꿣
멤버 생셩됨

Mock 과 Spy

테스트를 하는 객체에서 하나의 메소드에 대해서만 리턴값을 변경하고 싶을 때가 있다.
이러한 사항을 처리할 때 Mock 을 사용하여 처리하면 모든 메소드가 Mocking 처리되기 때문에 안된다.

이 때 Spy 를 사용하게 되면 하나의 메소드에 대한 Mocking 처리를 할 수 있다.

@ExtendWith(MockitoExtension.class)
public class UnitTest {

	@Mock
    TestConfig.MemberValidator memberValidator;

    @Mock
    TestConfig.EmailSender emailSender;

	@Spy // 실제 객체 Wrapping Mockito 객체 만듦
    @InjectMocks // 내부 의존 객체들 Mocking 처리
    TestConfig.MemberCreator memberCreator;
    

    @Test
    @DisplayName("멤버를 생성해 보자")
    public void createMember() {
        // given
        Long id = 1L;
        String name = "꿣꿣꿣";

		// 성공 메시지 메소드 호출시 아무것도 안함
        BDDMockito.doNothing()
            .when(memberCreator)
            .memberCreateSuccessMessage();
            
        // when
        Long result = memberCreator.create(id, name);

        // then
        assertThat(result).isEqualTo(id);
    }
    ... 중략
    
}

[결과]
id = 1
name = 꿣꿣꿣

MockBean 과 SpyBean

스프링 어플리케이션 컨텍스트에서 관리되는 Bean 객체를 Mockito 객체로 덮어씌움
Mock : 기존 기능을 모두 하지 않고 메소드 시그니처만 따라감
Spy: 기존 기능을 DefaultAnswer 로 수행, Stub 되어 있는 메소드 객체가 있으면 해당 기능을 수행

profile
뿌리를 생각하는 나무 개발자

1개의 댓글

comment-user-thumbnail
2022년 8월 4일

훌륭한 정리 감사합니다.

답글 달기