https://sundaland.tistory.com/79
Mockito는 자바에서 사용되는 인기 있는 모의 (Mocking) 프레임 워크이다. Mockito를 사용하면 테스트 중에 가 (Mock) 객체를 생성하고, 그 객체의 동작을 설정하고, 동작을 검증할 수 있다.
Mockito는 테스트 코드 작성을 더욱 쉽고 유연하게 만들어즈는 강력한 도구이다.
1. Mockito 설정
Mockito 라이브러리를 프로젝트에 추가해야 한다. 일반적으로 Maven, Gradle과 같은 의존성 관리 도구를 사용하여 아래와 같이 의존성을 추가할 수 있다.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
2. 목 (Mock) 객체 생성
@Mock 어노테이션을 사용하거나 Mockito.mock() 메서드를 사용하여 목 (Mock) 객체를 생성할 수 있다.
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
// @Mock 어노테이션을 사용한 목(Mock) 객체 생성
@Mock
private UserDao userDao;
public void setUp() {
MockitoAnnotations.openMocks(this);
}
// Mockito.mock() 메서드를 사용한 목(Mock) 객체 생성
UserDao userDao = Mockito.mock(UserDao.class);
3. 동작 설정
when().thenReturn()을 사용하여 목 (Mock) 객체의 메서드 호출에 대한 동작을 설정할 수 있다.
import static org.mockito.Mockito.when;
// userDao.getUserById() 메서드 호출 시 동작 설정
when(userDao.getUserById(1)).thenReturn(new User("John"));
# userDao.getUserById(1) 메서드가 호출되면 이름이 "John" 인 새로운 User 객체를 반환한다.
4. 동작 검증
verify() 메서드를 사용하여 목 (Mock) 객체의 메서드 호출이 예상대로 이루어졌는지 검증할 수 있다.
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;
// userDao.updateUser() 메서드가 한 번 호출되었는지 검증
verify(userDao, times(1)).updateUser(any(User.class));
// userDao.deleteUser() 메서드가 호출되지 않았는지 검증
verify(userDao, never()).deleteUser(anyInt());
Mockito는 다양한 기능을 제공하여 더 복잡한 테스트 시나리오를 처리할 수 있다. 예를 들어, 예외를 발생시키거나 순서에 따른 동작을 설정할 수 있다.
[ 자세한 설명 ]
1. Mock 객체 생성
Mock 객체는 실제 객체의 행동을 모방하는 객체로, 실제 코드의 외부 의존성을 대체한다.
1.1 기본 Mock 생성
Mockito.mock(Class) 메서드를 사용하여 mock 객체를 생성할 수 있다.
List mockedList = Mockito.mock(List.class);
1.2 어노테이션을 이용한 Mock 생성
@Mock 어노테이션을 사용하면 테스트 클래스 내에서 직접 mock 객체를 선언할 수 있다. 이를 위해 MockitoAnnotations.initMocks(this)를 테스트의 @BeforeEach 메서드에서 호출해야 한다.
@Mock
List mockedList;
@BeforeEach
public void init() {
MockitoAnnotations.initMocks(this);
}
2. Mock 객체의 행동 정의
Mock 객체의 행동을 when-thenReturn 패턴을 사용하여 정의할 수 있다.
2.1 when-thenReturn
특정 조건에서 특정 값을 반환하도록 설정한다.
Mockito.when(mockedList.get(0)).thenReturn("first element");
2.2 예외 던지기
특정 조건에서 예외를 발생시킬 수 있다.
Mockito.when(mockedList.get(anyInt())).thenThrow(new RuntimeException());
3. Mock 객체의 상호작용 검증
3.1 verify 메서드
특정 메서드가 특정 조건으로 호출되었는지 검증한다.
mockedList.add("one");
Mockito.verify(mockedList).add("one");
3.2 호출 횟수 검증
메서드가 특정 횟수만큼 호출되었는지 검증한다.
Mockito.verify(mockedList, Mockito.times(1)).add("one");
4. Argument Matchers
Mockito는 다양한 Argument Matchers를 제공하여 더 유연한 행동 정의와 검증을 가능하게 한다.
any(), eq(), refEq(), anyInt() 등 다양한 matchers를 사용할 수 있다.
Mockito.when(mockedList.get(anyInt())).thenReturn("element");
5. Spy 객체
Spy 객체는 실제 객체의 일부 행동을 모방하면서도 일부는 실제 객체의 행동을 유지하는 특별한 종류의 mock이다.
5.1 Spy 객체 생성
List list = new ArrayList();
List spyList = Mockito.spy(list);
5.2 Spy 객체의 행동을 부분적으로 오버라이드
Mockito.doReturn("first element").when(spyList).get(0);
6. Mock 객체의 리셋
테스트 중 Mock 객체의 상태를 리셋한 필요가 있을 때 사용한다.
Mockito.reset() 메서드를 사용하여 mock 객체를 초기 상태로 되돌린다.
Mockito.reset(mockedList);
Mockito는 단위 테스트를 위한 강력하고 유연한 도구이다. Mock 객체를 사용하여 실제 객체의 의존성을 제거하고, 테스트 대상의 독립성을 보장하여 보다 견고하고 유지보수가 용이한 테스트 코드를 작성할 수있다. Mockito의 다양한 기능을 활용하여, 복잡한 비즈니스 로직을 가진 애플리케이션의 테스트를 효율적으로 진행할 수 있다.
[ 예제 ]
UserService라는 사용자 서비스 클래스를 테스트하려고 한다. UserService는 UseDao와 EmailService에 의존하고 있다. 우리는 UserService의 동작을 확인하고자 하는데, UserDao의 메서드 호출이 제대로 이루어지고 EmailService에 이메일이 제대로 전송되는지를 확인하려고 한다.
1. 의존성 주입 (Dependency Injection)
의존하는 객체들 (UserDao, EmailService)를 Mock 객체로 대체해야 한다. 이를 위해 Mockito의 @Mock 어노테이션을 사용한다.
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class UserServiceTest {
@Mock
private UserDao userDao;
@Mock
private EmailService emailService;
@InjectMocks
private UserService userService;
public void setUp() {
MockitoAnnotations.openMocks(this);
}
// 테스트 메서드들...
}
@Mock 어노테이션은 UserDao와 EmailService의 목 객체를 생성한다. InjectMocks 어노테이션은 UserService 객체를 생성하고, 그 안에 목 객체들을 주입한다. setUp() 메서드는 목 객체들을 초기화하기 위해 MockitoAnnotations.openMocks(this)를 호출한다.
2. 메서드 동작 설정 및 검증
테스트 시나리오에 따라 목 객체들의 동작을 설정하고, 검증할 수 있다. 이를 위해 Mockito의 when()과 verify() 메서드를 사용한다.
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
public class UserServiceTest {
// ...
public void testAddUser() {
// UserDao 목(Mock) 객체의 동작 설정
when(userDao.addUser(any(User.class))).thenReturn(true);
// EmailService 목(Mock) 객체의 동작 설정
doNothing().when(emailService).sendWelcomeEmail(any(User.class));
// 테스트 대상 메서드 호출
User user = new User("John", "john@example.com");
boolean result = userService.addUser(user);
// UserDao 메서드 호출 검증
verify(userDao).addUser(user);
// EmailService 메서드 호출 검증
verify(emailService).sendWelcomeEmail(user);
// 결과 검증
assertTrue(result);
}
// ...
}
when() 메서드를 사용하여 userDao.addUser() 메서드가 호출될 때 true를 반환하도록 설정하였다. doNothing().when(emailService).sendWelcomeEmail()은 emailService.sendWelcomeEmail() 메서드가 호출될 때 아무 동작도 하지 않도록 설정했다. 그리고 verify() 메서드를 사용하여 userDao.addUser()와 emailService.sendWelcomeEmail() 메서드가 각가 한 번씩 호출되었는지를 검증한다.
3. 목 객체의 추가적인 검증
실제 메서드 호출 시 특정 매게변수를 사용하는지, 메서드 호출 횟수 등을 검증할 수 있다.
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;
public class UserServiceTest {
// ...
public void testUpdateUser() {
// UserDao 목(Mock) 객체의 동작 설정
when(userDao.getUserById(1)).thenReturn(new User("John", "john@example.com"));
// 테스트 대상 메서드 호출
boolean result = userService.updateUserEmail(1, "newemail@example.com");
// UserDao 메서드 호출 검증
verify(userDao).getUserById(1);
verify(userDao).updateUserEmail(1, "newemail@example.com");
verify(userDao, never()).updateUserName(anyInt(), anyString());
// EmailService 메서드 호출 검증
verify(emailService, times(1)).sendEmail(anyString(), anyString(), anyString());
// 결과 검증
assertTrue(result);
}
// ...
}
위 코드에서 userDao.getUserById() 메서드가 호출될 때 new User("John", "john@example.com")를 반환하도록 설정했다. userService.updateUserEmail() 메서드를 호출하고, userDao.getUserById() userDao.updateUserEmail() 메서드의 호출을 검증한다. userDao.updateUserName() 메서드는 호출되지 않아야 함을 never() 메서드로 검증한다.
emailService.sendEmail() 메서드는 한 번 호출되어야 함을 times(1)로 검증한다.
Mockito를 사용하여 목 객체를 생성하고, 동작을 설정하고, 동작을 검증하여 테스트 환경에서 의존성을 가진 객체들을 쉽게 모의 (Mock)할 수 있다.
'테스트 주도 개발 (TDD)' 카테고리의 다른 글
테스트 주도 개발 (TDD) (0) | 2024.08.08 |
---|---|
단위 테스트 (Unit Test) (0) | 2024.08.07 |
JUnit 5 (0) | 2024.08.07 |