StrutsTestCase for JUnit v2.1.4
Now supporting Struts 1.2 and 1.3, including Tiles and Sub-Applications!
Questions? Comments? Check out the user forums.
What is it?
JUnit를 위한 스트러츠 테스트 케이스는 표준 JUnit 테스트케이스를 확장한 것으로 스트러츠 프레임워크를 기반으로한 테스팅 수단이다. 스트러츠 테스트 케이스는 Mock Object approch와 Cactus approach 둘다 지원하며 실행하는 ActionServlet상에서 수행된다. 또한 실제 서블릿 엔진 구동없이 스트러츠 테스트 코드를 수행할 수 있도록 해준다. 스트러츠 테스트케이스는 ActionServlet를 이용하여 당신의 테스트 코드를 테스트 할 수 있기 때문에 당신은 Action 객체 뿐만 아니라 매핑, 폼빈과 포워드 선언까지 테스트 할 수 있다. 그리고 이미 벨리데이션 메소드를 지원하기 때문에 테스트 케이스를 매우 간단하고 쉽게 수행할 수 있도록 해 준다. 스트러츠 테스트케이스는 자바 서블릿 2.2, 2.3, 2.4의 환경에서 수행된다. 그리고 스트러츠 1.2/1.3과 Cactus 1.7과 JUnit 3.8.1상에서 수행된다.
스트러츠 테스트케이스는 더이상 스트러츠 1.0을 지원하지 않는다. 과거 스트러츠 1.0에 적합한 버젼은 StrutsTestCase v2.0. 임을 기억하기 바란다.
Where does it live?
스트러츠 테스트 케이스는 SourceForge에서 배포하고 있다. 최근 혹은 가장좋은 릴리즈 버젼을 여기here 서 찾을 수 있다.
모든 스트러츠 테스트케이스 클래스에 관한 자바 독 문서는 here에서 찾을 수 있으며 자주 질문해오는 frequently asked questions리스트와 토론 포럼discussion forum 이 있다.
Mock Testing vs. In-Container Testing
서버사이드 클래스 테스팅의 2가지 가장 인기있는 부분은 mock objects로 테스트 케이스를 서버 컨테이너 상에서 시뮬레이션 할 수 있는 방법과 in-container testing으로 테스트 클래스들이 실제 서버 상에서 수행되는 방법이다. 스트러츠 테스트케이스는 두가지 접근을 다 허용하고 있으며 아주작은 유닛테스트 코드만으로 수행할 수 있도록 지원한다. 사실 스트러츠 테스트 케이스 셋업과 벨리데이션 메소드는 정확히 두가지 접근을 모두 지원하기 때문에 하나의 접근 방법을 선택하더라도 간단한 베이스 클래스를 사용하는 것으로 효과를 볼 수 있다.
스트러츠 케스트케이스는 2개의 베이스 클래스를 제공한다. 두개는 표준 JUnit 테스트케이스를 확장한 것으로 MockStrutsTestCase를 사용하여 HttpServlet mock 객체를 실제 서블릿 엔진이 수행되지 않아도 시뮬레이션 할 수 있다. CactusStrutsTestCase는 Cactus testing framework를 이용하여 스트러츠클래스를 테스트 하며 실제 서버 컨테이너 상에서 수행된다. 실제 디플로이환경에 맞게 테스팅환경을 지원해준다.
MockStrutsTestCase접근을 이용하여 다음에 오는 예제를 수행할때 CactusStrutsTestCase를 다른 어떠한 코드의 추가없이 단순한 서브클래싱 만으로 Cactus로 변경하여 선택할 수 있는 기능도 제공된다.
How does it work?
스트러츠 테스트케이스의 배포는 이예제와 다음에 오는 예제들을 따라서 스텝바이스텝으로 실행하면 된다. README파일을 보면 좀더 상세한 내용을 볼 수 있다. 스트러츠 테스트케이스 라이브러리에는 많은 메소드가 존재하며 그것에 관해서는 여기서 보여줄 것이다. 자바 독 문서를 확인해 보면서 당신이 스트러츠 테스트케이스로 무엇을 할 수 있는지 확인해 보기 바란다.
가장 일반적인 쿡북 접근이다. 다음 코드 부분을 확인해보자.
public class LoginAction extends Action { public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { String username = ((LoginForm) form).getUsername(); String password = ((LoginForm) form).getPassword(); ActionErrors errors = new ActionErrors(); if ((!username.equals("deryl")) || (!password.equals("radar"))) errors.add("password",new ActionError("error.password.mismatch")); if (!errors.empty()) { saveErrors(request,errors); return mapping.findForward("login"); } // store authentication info on the session HttpSession session = request.getSession(); session.setAttribute("authentication", username); // Forward control to the specified success URI return mapping.findForward("success"); }
그래서, 우리가 여기서 무엇을 하고싶은 걸까? 우리는 ActionForm빈으로 부터 로그인 정보를 부여 받는다. 첫번째로 우리는 username과 password 정보를 받을 것이다. 그리고 그것이 적합한지 테스트 할것이다. 만약 username과 password가 일치하지 않는 값이 들어온다면 우리는 ActionError 메시지를 message 카탈로그의 키값으로 획득할 것이다. 그리고 로그인 화면으로 다시 로그인 하라는 메시지를 보내고 다시 로그인을 할 수 있을 것이다. 만약 username과 password가 일치한다면 인증 정보를 우리의 세션에 심을 것이다. 그리고 우리는 다음 페이지로 이동할 것이다.
이 테스트에서 몇가지 내용들을 확인할 수 있다.
- LoginForm빈은 적합하게 동작하고 있는가? 우리가 적당한 파라미터를 request에 제공한다면 이 것은 정확하게 수행될 것이다.
- 만약 username과 password가 일치하지 않는다면 적당한 에러를 다음 스크린에서 보여주기 위해서 저장할 것이다. 그리고 다시 로그인페이지로 돌아갈 것이다.
- 우리가 정확한 로그인 정보를 제공한다면 우리는 딱 맞는 페이지를 획득할 것이다. 거기에는 정말 에러없이 출력되는가? 정확한 인증 정보가 세션에 저장되는가?
스트러츠 테스트케이스는 이러한 조건에 대해서 잘 알려진 JUnit 프레임워크 테스트를 수행해 줄 것이다. 스트러츠 셋업의 모든것은 ActionServlet이 시작될때 얼마간으로 적용될것이며, 당신에 의해서 관리되어 질 것이다.
그래서 우리는 어떻게 이러한 작업을 할 것인가? 자 빈 테스트케이스를 만들자, 이것은 베이스 클래스가 StrutsTestCase 클래스를 상속 받아야 한다.
public class TestLoginAction extends MockStrutsTestCase { public void setUp() { super.setUp(); } public void tearDown() { super.tearDown(); } public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() {} }
NOTE : 당신이 만약 setUp 메소드를 오버라이드 하기를 결심했다면 당신은 반드시 super.setUp()를 호출해야만 한다. 이 메소드는 몇가지 중요한 초기화 루틴을 수행한다. 스트러츠 테스트케이스는 호출되지 않은경우 시행되지 않을 것이다.
우리가 이작업을 수행하기 위해서 첫번째로 필요한 것은 이 테스트에서 사용할 매핑을 설정하는 것이다. 그러한 작업을 해야 스트러츠 매핑과 특정한 패스를 연관시킬 수 있다. 이것은 스트러츠 태그 라이브러리 메소드를 사용하는 것과 동일한 메커니즘을 가진다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); } }
NOTE : 기본적으로 ActionServlet는 WEB-INF/struts-config.xml을 찾을 것이다. 그러므로 당시은 WEB-INF를 클래스패스에 포함시켜야 한다. 만약 다른 configuration 파일을 사용하고자 한다면 setConfigFile() 메소드를 보라 이것은 이 파일이 위치한 정보를 정확하게 보여준다.
다음으로 우리가 필요한 것은 빈 프로퍼티이다. 이것은 request 객체를 경유하여 전송된다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); } }
마지막으로 우리는 Action이 수행하는 것을 획득할 수 있다. actionPerform 메소드가 수행된것과 관련된 작업이 수행된다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); } }
저것이 ActionServlet이 당신이 요청한 request를 처리하는 작업이다. 그리고 어떠한 일도 일어나지 않을 것이다. 그러나 우리의 일은 아직 끝나지 않았다. 우리는 여전히 발생할 수 있는 모든 상황에 대해서 검증을 해야한다. 첫번째로 우리는 올바른 페이지로 진행하는지 확인해야 한다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyForward("success"); } }
당신이 끝에 올바른 페이지로 가는지에 대해서 스트러츠 forward 매핑을이용 할 수 있다. 당신은 파일 이름을 하드코딩 하지 않아도 된다. StrutsTestCase프레임워크는 이러한 것을 관리해준다. 그러므로 당신은 "success"가 어디로 가는지에 대한 포인팅만 변경해주는 경우 당신의 테스트는 여전히 잘 동작할 것이다.
다음으로 우리는 인증 정보를 적당하게 저장되기를 원할 것이다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyForward("success"); assertEquals("deryl",(String) getSession().getAttribute("authentication")); } }
여기에서 우리는 request로부터 세션 객체를 획득할 것이다. 그리고 적당한 속성과 값이 존재하는지 체크할 것이다. Action객체가 찾기를 기대하는 세션상의 객체를 쉽게 위치시킬 수 있을 것이다. 스트러츠 테스트케이스를 베이스로 하는 모든 서블릿 클래스들은 완전한 기능을 수행하는 객체이다.
마지막으로 우리는 ActionError 메시지와 같은 메소드를 혼자서 만들기를 원하지 않을 것이다. 우리는 이러한 상황에 대한 빌드인 메소드를 이용할 수 있다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setRequestPathInfo("/login"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyForward("success"); assertEquals("deryl",(String) getSession().getAttribute("authentication")); verifyNoActionErrors(); } }
우리가 많은 테스트 케이스를 보자, 이것은 매우 쉽게 작성할 수 있다. 예를 들어 우리는 아마도 잘못된 로그인 정보가 들어온 케이스에 대해 작성하 기를 원할 것이다. 우리는 다음과 같은 테스트케이스를 작성함으로 그것을 달성할 수 있다.
public void testFailedLogin() { addRequestParameter("username","deryl"); addRequestParameter("password","express"); setRequestPathInfo("/login"); actionPerform(); verifyForward("login"); verifyActionErrors(new String[] {"error.password.mismatch"}); assertNull((String) getSession().getAttribute("authentication")); }
이것은 첫번째 테스트케이스와 매우 유사하게 보인다. 우리는 잘못된 정보를 패싱하기를 원할 것이다. 그리고 우리는 또한 다른 포워드를 사용하기를 원할 것이다. 다시말해 로그인 페이지로 이동하기를 원하며 인증 정보가 세션에 들어가는 것을 원치 않을 것이다.
또한 정확한 에러 메시지를 보내기를 원한다. 우리는 실제적인 텍스트가 아니라 심볼릭 이름을 사용했음을 주시하자. verifyActionErrors() 메소드가 스트링 배열을 다루기 때문에 우리는 하나 이상의 에러 메시지를 검증할 수 있다. 그리고 StrutsTestCase는 정확하게 매치되는 값을 만들 수 있을 것이다. 만약 우리가 기대한것 보다 더 이상의 에러 메시지가 생성되었다면 그것은 실패한 것이다. 만약 몇개 안된다면 그것또한 실패가 된다. 오직 정확하게 매칭되는 이름과 숫자가 되어야 통과한 것이다.
그것은 매우 쉽다. 당신이 보는바와 같이 StrutsTestCase는 당신의 Action Object를 구현하는것 뿐만 아니라. ActionForm 빈이 전달하는 아규먼트와 에러메시지 그리고 실행결과로 부터 생성되는 포워딩 구문까지 매핑하여 실행할 수 있다. 그것은 매우 값진것이라 할 수 있다.
Testing Tiles in Struts 1.2
타일즈 프레임워크 스트러츠 1.2에 통합된 것으로 유동적인 템플릿을 지원하여 사용자 경험의해서 공통적으로 재 사용성을 쉽게 할 수 있도록 디자인된 메커니즘이다. 스트러츠 테스케이스는 타일즈를 이용하여 테스팅을 할 수 있도록 지원하고 있다. 정확한 타일즈 정의를 이용하여 액션을 검증할 수 있다. 타일즈 테스팅은 verifyActionForward를 호출하는 것과 유사하게 테스팅된다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setConfigFile("/WEB-INF/struts-config.xml"); setRequestPathInfo("/login.do"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyTilesForward("success","success.tiles.def"); } }
이것은 우리가 이전에 보았던 테스트케이스와 유사하다. 우리는 기대하는 포워드를 풀어나갈때 주어진 타일즈 정의를 이용하여 Action에 대한 검증을 하도록 한다. 우리가 다른 타일즈 정의를 이용한다고 하고, 기대하는 정의가 존재하지 않는다면 테스트는 실패하게 된다. 추가적으로 verifyInputTilesForward를 호출하면 입력 매핑을 이용하는 Action을 검증할 수 있으며 타일즈 정의에 의해 기대했던 입력 매핑에 대해서 확인 할 수 있다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setConfigFile("/WEB-INF/struts-config.xml"); setRequestPathInfo("/login.do"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyInputTilesForward("success.tiles.def"); } }
Testing Sub-Applications in Struts 1.2
스트러츠 1.2의 서브 애플리케이션과 모듈의 개념을 소개한다면 기능적으로 컴포넌트를 나누는 강력한 메커니즘이다. 스트러츠 테스트케이스는 서브 애플리케이션을 테스트를 지원하기 위해 제공된다. 이것은 이전 예제에서 다루었던 내용이다. 일반적은 아이디어는 여전히 같다. 당신은 설정파일을 통해서 유닛테스트를 할 수 있고, 액션을 실행하거나 결과를 검증할 수 있다. 설정 파일을 위한 메소드와 조금다른 실행중인 액션에 대해서 다음 예제를 보면서 확인해 볼것이다.
public class TestLoginAction extends MockStrutsTestCase { public TestLoginAction(String testName) { super(testName); } public void testSuccessfulLogin() { setConfigFile("mymodule","/WEB-INF/struts-config-mymodule.xml"); setRequestPathInfo("/mymodule","/login.do"); addRequestParameter("username","deryl"); addRequestParameter("password","radar"); actionPerform(); verifyForward("success"); assertEquals("deryl",(String) getSession().getAttribute("authentication")); verifyNoActionErrors(); } }
보는것과 같이 다른 테스트케이스와 매우 유사하다. 첫번째 중요한 차이점은 설정파일 세팅이 다르다. 여기서는 파일과 주어진 서브 애플리케이션 이름에 대한 속성 파일이다. 이것은 스트러츠 테스트케이스 라이브러리에 이러한 설정 정보들에 대해서 ActionServlet가 서브 애플리케이션을 정확하게 구분할 수있도록 한다. 유사한 예로 이전에 언급한 CLASSPATH에 위치한 속성정보를 세팅하는 것을 기억하기 바란다.
다른 중요한 차이점은 request path 정보를 세팅하는 것이다. 여기에 우리는 패스 정보뿐만 아니라. 서브 애플리케이션의 이름까지 지정한다. 이러한 두개의 파라미터 조합은 전체 request 패스와 동일하다. 우리가 본 상단의 테스트 케이스에서 패스가 /mymodule/login.do와 같다. 이것은 이 메소드를 이용할때 매우 중요한 것으로 첫번째 아규먼트는 반드시 서브 애플리케이션 이름이 포함되어야 한다 그리고 다음 아규먼트는 서브 애플리케이션의 이름이 포함되지 않은 패스가 와야한다. 반면 리퀘스트 패스가 잘못 생성되었다면 결과는 실패할 것이다.
'WEB_Programming > Struts' 카테고리의 다른 글
Select Tag<html:select>: 사용법 (0) | 2008.06.10 |
---|---|
Textarea Tag<html:textarea>: 사용법 (0) | 2008.06.10 |
Checkbox Tag <html:checkbox>: 사용법 (1) | 2008.06.10 |
Hidden Tag <html:hidden> : 사용법 (0) | 2008.06.10 |
스트러츠 태그 기본 (0) | 2008.06.10 |