아래와 같은 예시 코드가 있다.
@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 을 사용하여 처리하면 모든 메소드가 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 = 꿣꿣꿣
스프링 어플리케이션 컨텍스트에서 관리되는 Bean 객체를 Mockito 객체로 덮어씌움
Mock : 기존 기능을 모두 하지 않고 메소드 시그니처만 따라감
Spy: 기존 기능을 DefaultAnswer 로 수행, Stub 되어 있는 메소드 객체가 있으면 해당 기능을 수행
훌륭한 정리 감사합니다.