요즘 저에게 가장 화두가 되고 있는 단어 중에 하나가 바로 “테스트“입니다.
어떻게 하면, 테스트케이스를 통해 실제 코드를 더욱 견고하고 깔끔하게 만드는가 하는데에
따른 고민에서 시작됩니다.
바로 그 시작점인 “테스트“케이스를 만드는데 있어, 현재 가장 많이 쓰이고 있는
프레임워크인 “스프링“에서 웹 어플리케이션의 서버사이드 “프론트“를 담당하고 있는
“Contoller”부분에 대한 간단한 CRUD 테스트케이스를 만들어 보았습니다.
public class TempVo { private Integer id; private String name; ... 이하 setter/getter코드 생략 }
public interface TempService { TempVo getListUserInfo(int id); int insertUserInfo(TempVo temp); int updateUserInfo(TempVo temp); int deleteUserInfo(TempVo temp); List getListTemp(); }
import static com.glider.framework.test.ReflectionInjectorUtils.injector; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.web.servlet.ModelAndView; import com.google.common.collect.Lists; @RunWith(MockitoJUnitRunner.class) public class CommonControllerTest { // 테스트대상 클래스의 의존객체에 Mock Object 주입 @Mock private TempService tempService; // 테스트대상 클래스에 Mock Object 주입 @InjectMocks private CommonController commonController = new CommonController(); private ModelAndView model; @Before public void setUp() { // 테스트대상 Mock 클래스에 의존 Mock객체를 쉽게 주입할 수 있음. // http://wiki.kwonnam.pe.kr/java/unittest/reflectioninjector 참고. injector(commonController).set(tempService); model = new ModelAndView(); } @Test public void getTemp() { int id = 1; TempVo temp = new TempVo(); when(tempService.getListUserInfo(id)).thenReturn(temp); commonController.temp(id, model); verify(tempService).getListUserInfo(id); assertThat(model.getViewName(), is("temp/temp")); } @Test public void insertTemp(){ TempVo temp = new TempVo(); temp.setId(1); temp.setName("bluepoet"); when(tempService.insertUserInfo(temp)).thenReturn(1); commonController.insertTemp(name, model); verify(tempService).insertUserInfo(temp); assertThat(model.getViewName(), is("temp/temp")); } @Test public void updateTemp() throws Throwable { TempVo temp = new TempVo(); temp.setId(3); temp.setName("bluepoet"); when(tempService.updateUserInfo(temp)).thenReturn(1); commonController.updateTemp(name, model); verify(tempService).updateUserInfo(temp); assertThat(model.getViewName(), is("temp/temp")); } @Test public void deleteTemp() throws Throwable { TempVo temp = new TempVo(); temp.setId(1); temp.setName("bluepoet"); when(tempService.deleteUserInfo(temp)).thenReturn(1); commonController.deleteTemp(name, model); verify(tempService).deleteUserInfo(temp); assertThat(model.getViewName(), is("temp/temp")); } @Test public void getListTemp() { List list = Lists.newArrayList(); when(tempService.getListTemp()).thenReturn(list); commonController.getListTemp(model); verify(tempService).getListTemp(); assertThat(model.getViewName(), is("temp/tempList")); } }
물론 CRUD Controller 메서드안에 더욱 복잡한 로직이 들어갈 수도 있습니다.
그럴땐, 테스트케이스가 더 복잡해지겠지요.
다만, 큰 것을 만들때는 작은 것부터 Step by Step으로 나가는 것이 좋다고 생각합니다.
스프링 framework에서 controller를 만들때는 위 테스트케이스를 뼈대로 해서,
테스트케이스를 확장해나가시면 더욱 견고한 real code를 만드실 수 있으리라고 봅니다.
단위테스트에 대해서는 토비의 스프링3에서도 여러차례 리팩토링과 함께 잘 나와있으니
참고하시면 될것 같구요(테스트대역, 스텁, Mock Object의 개념등..)
아래 포스팅에서는 테스트케이스를 작성하는 방법과 활용에 대해서 더욱 잘 나와있으니
꼭 일독을 권해드립니다.
* 참고 url
- Spring에서 단위테스트시 객체 주입 쉽게 하기 ReflectionInjector (http://kwon37xi.egloos.com/4664011)
- Mockito를 이용한 MockTest(http://javacan.tistory.com/148)
- Mockito 테스트 프레임워크를 활용해 Bean Inject 하기 (http://javajigi.tistory.com/tag/InjectMocks)
- 왜 Mockito가 좋은가? (http://kwon37xi.springnote.com/pages/3600137)
오오~좋은 내용 잘봤습니다. 요즘 저도 형님 코드 보면서 tdd공부하고 있습니다 ㅎ 근데 어렵네요 ㅠㅠ 토요날 뵈요