UserDao를 인터페이스로 만들고
기존의 UserDao는 UserDaoJdbc로 이름을 바꾸었다.
UserServcieTest의 upgradeLevels()테스트에 적용해보자
MockUserDao
package springbook.user.dao;
import java.util.ArrayList;
import java.util.List;
import springbook.user.domain.User;
public class MockUserDao implements UserDao{
// 레벨 업그레이드 후보 목록 User 오브젝트
private List<User> users;
// 업그레이드 대상 오브젝트를 저장해둘 목록
private List<User> updated = new ArrayList<User>();
public MockUserDao(List<User> users) {
this.users = users;
}
public List<User> getUpdated(){
return this.updated;
}
// 스텁 기능 제공
@Override
public List<User> getAll(){
return this.users;
}
// 목 오브젝트 기능 제공
@Override
public void update(User user) {
updated.add(user);
}
// 사용하지 않는 메소드는 UnsupportedOperationException 예외를 던진다.
@Override
public void add(User user) {throw new UnsupportedOperationException(); }
@Override
public User get(String id) {throw new UnsupportedOperationException();}
@Override
public void deleteAll() {throw new UnsupportedOperationException();}
@Override
public int getCount() {throw new UnsupportedOperationException();}
}
이제 upgradeLevels()테스트가 MockUserDao를 사용하도록 수정하자.
@Test
public void upgradeLevels() throws Exception {
//고립된 테스트에서는 테스트 대상 오브젝트를 직접 생성하면된다.
UserServiceImpl userServiceImpl = new UserServiceImpl();
//목 오브젝트로 만든 UserDao를 직접 DI해준다.
MockUserDao mockUserDao = new MockUserDao(this.users);
userServiceImpl.setUserDao(mockUserDao);
MockMailSender mockMailSender = new MockMailSender();
userServiceImpl.setMailSender(mockMailSender);
userServiceImpl.upgradeLevels();
//MockUserDao로부터 업데이트된 결과를 가져온다.
List<User> updated = mockUserDao.getUpdated();
assertEquals(updated.size(), 2);
checkUserAndLevel(updated.get(0), "joytouch", Level.SILVER);
checkUserAndLevel(updated.get(1), "madnite1", Level.GOLD);
List<String> request = mockMailSender.getReuests();
assertEquals(request.size(), 2);
assertEquals(request.get(0), users.get(1).getEmail());
assertEquals(request.get(1), users.get(3).getEmail());
}
// id와 level을 확인하는 메소드
private void checkUserAndLevel(User updated, String expectedId, Level expectedLevel) {
assertEquals(updated.getId(), expectedId);
assertEquals(updated.getLevel(), expectedLevel);
}
pom.xml
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
</dependency>
UserDao 인터페이스를 구현한 테스트용 목 오브젝트는
다음과 같이 Mockito의 스태틱 메소드를 한 번 호출해주면 만들어진다.
import static org.mockito.Mockito.mock;
//...
UserDao mockUserDao = mock(UserDao.class);
다음은 mockUserDao.getAll()이 호출됐을때 users리스트를 리턴해주라는 선언이다.
when(mockUserDao.getAll()).thenReturn(this.users);
mockUserDao의 update()메소드가 두 번 호출됐는지 확인하고 싶다면
다음과 같은 검증코드를 넣어주면된다.
verify(mockUserDao, times(2)).update(any(User.class));
//User타입의 오브젝트를 파라미터로 받는 update()메소드가 2번 호출됐는지 확인하라는 것이다.
Mockito를 적용한 테스트 코드
//...
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
//...
@Test
public void upgradeLevels() throws Exception {
UserServiceImpl userServiceImpl = new UserServiceImpl();
UserDao mockUserDao = mock(UserDao.class);
when(mockUserDao.getAll()).thenReturn(this.users);
userServiceImpl.setUserDao(mockUserDao);
MailSender mockMailSender = mock(MailSender.class);
userServiceImpl.setMailSender(mockMailSender);
userServiceImpl.upgradeLevels();
//레벨 검증
verify(mockUserDao, times(2)).update(any(User.class));
verify(mockUserDao).update(users.get(1));
assertEquals(users.get(1).getLevel(), Level.SILVER);
verify(mockUserDao).update(users.get(3));
assertEquals(users.get(3).getLevel(), Level.GOLD);
ArgumentCaptor<SimpleMailMessage> mailMessageArg =
ArgumentCaptor.forClass(SimpleMailMessage.class);
verify(mockMailSender, times(2)).send(mailMessageArg.capture());
List<SimpleMailMessage> mailMessages = mailMessageArg.getAllValues();
assertEquals(mailMessages.get(0).getTo()[0], users.get(1).getEmail());
assertEquals(mailMessages.get(1).getTo()[0], users.get(3).getEmail());
}
MailSender의 경우는 ArgumentCaptor라는 것을 사용해서
실제 MailSender 목 오브젝트에 전달된 파라미터를 가져와
내용을 검증하는 방법을 사용했다.
파라미터를 직접 비교하기 보다는 파라미터의 내부 정보를 확인해야 하는 경우에 유용하다.
[6.3] 다이나믹 프록시와 팩토리 빈 (0) | 2020.11.02 |
---|---|
[6.1] 트랜잭션 코드의 분리 (0) | 2020.11.02 |
[5.2] 트랜잭션 서비스 추상화 (0) | 2020.10.31 |
[5.1] 사용자 레벨 관리 기능 추가 (0) | 2020.10.30 |
[3.6] 스프링의 JdbcTemplate (0) | 2020.10.29 |
댓글 영역