블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Python 공부 노트 5. - 단위 테스트

프로그래밍/Python | 2013.01.21 00:10 | Posted by 조대협

단위테스트는 자바의 JUnit과 사상이 기본적으로 같음


import unittest


class SimpleTest(unittest.TestCase):

        @classmethod

        def setUpClass(cls):

            print("set up class")

            return

        

        @classmethod

        def tearDownClass(cls):

            print("tearDown class")

            

        def setUp(self):

            print("this is setup")

            return

            

        def tearDown(self):

            print("this is tear down")

            return

            

        def testSimple(self):

            self.assert_(1==2, "my assert failed")

            

        def testSecond(self):

            self.assertEqual(2, 2, "equal fails")

 

if __name__ == '__main__':

    unittest.main()           

#suite = unittest.TestLoader().loadTestsFromTestCase(SimpleTest)

#unittest.TextTestRunner(verbosity=2).run(suite)

  • setUpClass : 해당 클래스에서 테스트 시작시 한번만 사용됨. 초기 테스트 값 로딩이나 초기화
  • setUp : 테스트케이스 실행될때 마다 사용됨
  • tearDownClass: 해당 테스트 클래스 종료시 한번만 사용됨. (테스트 종료시 자원 정리등)
  • tearDown : 각 테스트 케이스 종료시 마다 사용됨
  • 테스트 케이스는 testXXX 로 시작됨
- 간단하게 unittest.main() 호출해서 시작할 수 도 있고, 별도의 TestSuite을 만들어서 테스트 가능
- 자체 프레임웍으로 LoadTest도 가능 - http://docs.python.org/2/library/unittest.html#load-tests-protocol
- Hudson (Jekins)연동은 Python을 이용하여 수행 - http://www.jython.org/jythonbook/en/1.0/TestingIntegration.html

아예 부하 테스트는 multi-mechanize를 이용해 가능. (작년에 보던 놈인데, 이제 파이썬 볼줄 아니까는 테스트 할 듯 있을듯)
http://testutils.org/multi-mechanize/
국내에서는 nGrinder가 많이 사용됨



확장된 단위 테스트 도구

(Cactus & JUnitEE)

 

자바스터디 조대협 (http://bcho.tistory.com)

 지금까지 기본적인 단위 테스트 도구에 대해서 알아보았다.

좀더 상세화된 단위 테스트의 단계를 나눠 보면 다음과 같이 나눠볼 수 있다. 

l        Type 1.코드 단위 테스트

코드상의 로직에 대해서만 테스트를 수행한다.앞 장에서 살펴본 테스트 방법이 일반적인 코드 단위 테스트 방법이다.

그러나 EJB,Servlet과 같은 J2EE 컴포넌트에 대해서 로직이 Dependency를 가지는 경우에는 EJB,Servlet 객체를 직접 연동하는 경우 container (WAS)에 배포하고, 기타 환경 설정이 필요하기 때문에, 로직 테스트를 위해서는 container 환경을 구성하기 전에 동일한 인터페이스를 가지면서 실제 로직은 없고 간단한 return값만 주는 가상의 객체 (Mock Object)이용해서 테스트 한다. Mock Test의 경우는 Spring IOC (Inversion of control)의 기능을 이용하면 좀더 쉽게 테스트할 수 있다. 

l        Type 2. In-Container 테스트

In container테스트는 , 컴포넌트들의 상호 작용과 컴포넌트와 컨테이너간의 상호작용을 테스트 하는 케이스 인데, POJO기반의 객체의 경우 문제가 없지만 J2EE와 같이 Container 위에서 동작하는 컴포넌트인 경우 Container에 배포하고, Container내에서 테스트 케이스를 수행해야 한다.

예를 들어 Servlet 클래스는 WAS환경 위에서만 작동하기 때문에, 테스트 하기 위해서는 JUnit이용하여 Pure Java환경에서는 테스트할 수 없으며 반드시 WAS 환경위에서 테스트가 필요하다. 이렇게 Container 환경내에서 테스트하는 것을 in-container 테스트라 하며,이를 지워하는 테스트 프레임웍으로는 JUnitEE Apache Cactus 테스트이 있다.  

l        Type 3. Acceptance 테스트

사용자 요구 사항에 대한 기능 테스트 이다. 좀더 쉽게 설명하면 사용자의 Use Case에 대한 시나리오에 따라 테스트를 하는것인데, 예를 들어 사이트에 LogIn해서 Form에 어떤 값을 넣고 submit 버튼을 누르면 화면상에 어떤 데이터가 출력되어야 한다는 등의 기능적 시나리오에 대한 테스트 이다. HTML 기반의 기능 테스트를 지원하는 테스트 프레임웍으로는 HttpUnit과 이를 확장한 JWebUnit등이 있다. 

l        Type 4.성능 단위 테스트

Type 1~3는 기능에 대한 테스트를 수행하였다면, Type 4는 비기능적인 이슈중에서 성능에 대한 테스트 방법으로, 각 단위 컴포넌트의 수행 시간에 대한 테스트를 수행하는 것이다. 성능 단위 테스트를 지원하는 프레임웍으로는 JPerfUnit등이 있다. 

지금까지 확장된 단위 테스트 방법에 대해서 살펴보았다. 지금부터는 이런 확장된 단위테스트를 수행할 수 있는 구체적인 테스트 프레임웍에 대해서 소개하고자 한다. 

(1)  In-container test - Catcus & JUnitEE

Type 2에서 언급한 in-container 테스트를 위한 프레임웍으로는 Apache Catcus JUnitEE이 있다.

두 프레임웍 모두 In-container 테스트를 가능하게 해주지만, JUnitEE의 경우 Catcus에 비해서 상대적으로 사용하기가 쉽다.JUnit TestCase를 구현해주고 JUnitEE의 서블릿을 설치하면, WAS에 리모트로 테스트를 수행할 수 있으며, 웹브라우져로도 테스트가 가능하다.

 Catcus의 경우 사용법은 JUnitEE에 비해서는 비교적 어렵지만, Servlet,JSP,TagLib에 대한 좀더 전문화된 테스트 프레임웍을 제공한다. 

 

EJB의 경우 Remote Interface가 있는 경우에는 In-container가 아니더라도 WAS외부에서 JUnit이용해서 테스트가 가능하지만, Local Interface만 구현한 경우에는 In-container 테스트만 가능하다. Servlet,JSP를 제외한 EJB,JMS,JNDI등의 J2EE컴포넌트들은 In-container test가 아니더라도, JUnit이용하여 리모트로 테스트 하는 것이 가능하다.

그러나 J2EE 솔루션 패키지(EAI,EP,ESB) 의 경우 J2EE의 호출 환경이 container 내에서만 호출되도록 디자인된 경우도 있기 때문에 필수적으로 In-container 테스트를 진행해야 할경우도 있다.

 In-container test의 경우 별도의 테스트 프레임웍 도입에 대한 비용(시간과 교육)이 필요한 만큼 필요성에 대해 고민한 다음 도입 여부를 결정하는 것이 필요하다.

 

 1)    JUnitEE

JUnitEE는 단순하게, TestCase를 컨테이너 안에서 수행할 수 있게 해주는데 그 목적을 둔다. 앞에서 작성한 JUnit 테스트 클래스인 HelloWorldTest EmpDAOTest Tomcat 컨테이너 안에서 수행해보자

 먼저 JUnit,DBUnit,JUnitEE 라이브러리를 다운로드 받은 후 dbunit-2.2.jar,junit.jar junitee.jar webapp WEB-INF/lib 디렉토리에 복사한다.

WEB-INF/web.xml JUnitEETestServlet을 아래와 같이 설정한다.

 

  <servlet>

    <servlet-name>JUnitEETestServlet</servlet-name>

    <description>JUnitEE test framework</description>

    <servlet-class>org.junitee.servlet.JUnitEEServlet</servlet-class>

  </servlet>

 

  <servlet-mapping>

    <servlet-name>JUnitEETestServlet</servlet-name>

    <url-pattern>/TestServlet/*</url-pattern>

  </servlet-mapping>

< 예제. JUnitEE 테스트 서블릿 설치 >

WEB-INF/testCase.txt라는 파일을 아래와 같이 작성한다. 이 파일에는 TestCase 클래명을 정의한다. 이 클래스명으로 JUnitEE가 단위테스트를 실행할 수 있게 된다.

# test Case Def

bcho.test.HelloWorldTest

bcho.simpledb.test.EmpDAOTest

<예제. JUnitEE에서 테스트 클래스를 지정하는 방법 >

위의 방법은 testCase.txt이용하여 TestCase를 지정하는 방법인데, 그 외에도 JUnitEEWar Ant task이용하여 자동으로 testCase.txt를 생성해낼 수 도 있으며 또는 web.xml servlet init parameter testCase가 들어있는 jar파일을 지정하는 방법등을 이용하여 테스트 케이스 클래스를 지정할 수 있다.

다음으로 Tomcat을 기동한후 http://ip:port/webapp_contextname/TestServlet을 수행한다.

사용자 삽입 이미지

<그림. JUnitEE의 테스트 선택화면 >

웹 화면상에서 등록한 테스트 케이스를 확인할 수 있으며 선택해서 테스트를 진행하게 되면, 다음과 같이 결과를 웹상으로 확인할 수 있다.

사용자 삽입 이미지
< 그림 JUnitEE의 테스트 결과 >

간단하게 JUnitEE이용해서 In-container 테스트를 수행하는 방법에 대해서 알아보았다.EJB JMS같은 J2EE컴포넌트들 역시 같은 방법으로 테스트가 가능하다.

또한 예제의 테스트 방법은 웹브라우져를 통해서 테스트를 수행하는 방법이었는데, 이 외에도 ant task이용해서 ant이용하여 테스트 자동화에 포함하는것도 가능하다. 

2)     Cactus

( http://jakarta.apache.org/cactus/)

또다른 in-container 단위 테스트 프레임웍인 Cactus  에 대해서 알아보자, Cactus Apache 자카르타 프로젝트의 일부로,JUnitEE JUnit 클래스를 서버에서 단순호출 해주는데 비해서 Cactus J2EE컴포넌트에 대한 좀더 정교한 테스트를 지원한다.

Cactus에서 지원하는 J2EE 컴포넌트로는 Servlet/JSP, Filter, TagLib,EJB 테스트들이 있으며, 이러한 테스트를 위한 클래스들을 지원한다.

 예를 들어 Servlet을 테스트하고자 할 때 JUnitEE를 사용하면 단순한 Java 객체로밖에 Servlet을 테스트할 수 밖에 없다. 그러나Servlet을 제대로 테스트하기 위해서는 HttpRequest 내용을 채워넣고, Servlet을 수행한후 Cookie Session 값들을 체크하고, HttpResponse의 내용을 체크해야 한다. 이런 일련의 작업들을 개발자가 일일이 Pure Java Code이용해서 테스트 코드를 만들어내기란 여간 까다로운 작업이 아니다.

 Cactus에서는 이러한 HttpRequest,Cookie,HttpReponse,Session,ServletConfig Servlet을 테스트하기 위해서 필요한 클래스들을 내장 클래스 형식으로 지원하여 쉽게 Servlet을 테스트할 수 있도록 해준다.

 JSP ServletFilter들도 마찬가지 원리로 지원해주게 된다. 

이해를 돕기 위해서 간단한 서블릿을 테스트하는 환경을 만들어보자.

서블릿은 Http Request를 통해서 id passwd를 입력받고, 이 값을 비교해서 맞으면 session id값을 저장하고 Login이 성공하였음을 response로 보내는 간단한 서블릿이다.

public class LogInServlet extends HttpServlet {

 

  public void doGet(HttpServletRequest req, HttpServletResponse res)

      throws ServletException, IOException {

 

    PrintWriter out = res.getWriter();

    HttpSession session = req.getSession();

 

    String id = req.getParameter("id");

    String passwd = req.getParameter("passwd");

 

    if(checkLogin(id,passwd)){

        // 로그인이 성공하였으면 세션에 ID 저장한다.

        session.setAttribute("id", id);

          out.print(id+" Login failed");

    }

   

    out.print(id+" Login success");

}// doGet

:

 

< 테스트할 서블릿 > 

이 서블릿을 테스트하기 위해서 Cactus로 테스트 케이스를 만든후, id passwd HttpRequest로 보낸후, session id가 저장되는지 확인한후, HttpResponse“success” 라는 문자열을 리턴하는지 확인하면,  서블릿이 정상적으로 동작하는 것을 확인할 수 있다.

Cactus로 만드는 테스트 클래스는 org.apache.cactus.ServletTestCase를 상속 받아서 구현되어야 하며, beginXXX testXXX,endXXX 메서드를 구현해야 한다.

beginXXX메서드는 test를 수행하기 전에 WebRequest 객체를 받아서 HttpRequest를 만드는 역할을 하고, testXXX에서는 실제로 테스트를 수행하며, endXXX에서는 Servlet의 수행이 끝난후에 WebResponse 객체를 받아서 HttpResponse 내용으로 테스트 결과를 검증하는 과정을 거친다. 

아래 샘플코드를 살펴보자

package bcho.servlet.test.catcus;

 import org.apache.cactus.Cookie;

import org.apache.cactus.ServletTestCase;

import org.apache.cactus.WebRequest;

import org.apache.cactus.WebResponse;

 import bcho.servlet.LogInServlet;

 public class TestLogInServlet extends ServletTestCase{

       public void beginLogin(WebRequest theRequest)

       {

             theRequest.addParameter("id", "bcho");

             theRequest.addParameter("passwd","passwd");

       }

       public void testLogin()

       {

           LogInServlet servlet = new LogInServlet();

             try{

                 servlet.init(config);

                

                 // Call method to test

                 servlet.doGet(request, response);

           }catch(Exception e){

               e.printStackTrace();

               assertTrue(false); // Exception 발생하였을 경우 실패로 간주한다.

               return;

           }

           // Perform some server side asserts

      

           assertEquals("bcho", session.getAttribute("id"));

       }

 

       public void endLogin(WebResponse theResponse)

       {

           // Asserts the returned HTTP response

             // 리턴되는 HTML 로그인 성공 메세지가 있는지 확인한다.

             String responseTxt = theResponse.getText();

             assertTrue(responseTxt.indexOf("success") > 0);

            

       }

 

}

< Cactus 서블릿 테스트 케이스 >

 beginLogin에서 request객체에 addParameter id passwd를 저장한다.testLogin에서 servlet.doGet을 수행하고, session“id”“bcho”라는 문자열이 저장되었는지 확인한다.endLogin에서는 servlet에서 나온 HttpResponse“success”라는 문자열이 있는지를 확인한다.

서블릿과 서블릿 테스트 클래스가 완성되었으면 이 환경을 서버에 배포해서 테스트를 수행해보자.

먼저 WEB-INF/lib 디렉토리에 http://jakarta.apache.org/cactus 에서 다운 받은 cactus 관련 라이브러리를 복사한다.

( cactus.jar , common-httpclient.jar,common-logging.jar, junit.jar , aspectjrt.jar ) 다음으로 위에서 만든 서블릿 클래스들을 WEB-INF/classes의 패키지 디렉토리에 알맞게 복사한다. 

다음으로 cactus 서블릿들인 ServletRedirector ServletTestRunner 클래스를 WEB-INF/web.xml에 다음과 같이 설정한다.

<?xml version="1.0" encoding="UTF-8"?>

<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name> Einstein Unit Tester Web Application </display-name>

       <servlet>

         <servlet-name>ServletRedirector</servlet-name>

         <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class>

         <init-param>

           <param-name>param1</param-name>

           <param-value>value1 used for testing</param-value>

         </init-param>

       </servlet>

     

       <servlet>

         <servlet-name>ServletTestRunner</servlet-name>

         <servlet-class>org.apache.cactus.server.runner.ServletTestRunner</servlet-class>

       </servlet>

      

       <servlet-mapping>

           <servlet-name>ServletRedirector</servlet-name>

           <url-pattern>/ServletRedirector</url-pattern>

       </servlet-mapping>

      

       <servlet-mapping>

           <servlet-name>ServletTestRunner</servlet-name>

           <url-pattern>/ServletTestRunner</url-pattern>

       </servlet-mapping>

 

      

</web-app>

 

 서버를 기동하고, 웹브라우져에서 다음과 같은 URL로 접근하면 테스트 결과를 얻을 수 있다.

http://{ip}:{port}/{context-root}/ServletTestRunner?suite={서블릿테스트클래스명}

 필자는 localhost 8080포트에서 context-root Catcus로 배포하였고, 테스트 서블릿은 위에서 작성한데로, bcho.servlet.test.catcus.TestLogInServlet으로 구성하였기 때문에, 테스트 URL은 아래와 같이 구성 된다.

 http://localhost:8080/Catcus/ServletTestRunner?suite=bcho.servlet.test.catcus.TestLogInServlet

 브라우져에서 테스트해서 테스트가 성공하면 다음과 같은 결과를 얻을 수 있다. 

사용자 삽입 이미지

XML 형식이 아니라 좀더 정재되고 보기 편한 형태로 테스트 리포트를 보고 싶을 경우에는 Apache Jakarta 프로젝트에서 제공하는 XSL을 적용하면 되는데, XSLhttp://jakarta.apache.org/cactus/misc/cactus-report.xsl 에서 다운 받을 수 있다.

다운 받은 cactus-report.xsl WebApplication context-root 디렉토리에 저장한후에 QueryString으로 xsl=cactus-report.xsl xsl 파일을 다음과 같이 지정할 수 있다. http://localhost:8080/Catcus/ServletTestRunner?suite=bcho.servlet.test.catcus.TestLogInServlet&xsl=cactus-report.xsl

 XSL을 저장하여 리포트를 생성한 결과는 다음과 같다. 

사용자 삽입 이미지

지금까지 Catcus이용해서In-container 테스트를 하는 방법을 살펴보았다.

테스트를 브라우져에서 진행하였는데, 단위테스트는 위에서도 설명하였듯이 빌드 작업의 일부로 진행이 되고, 빌드는 통상적으로 자동화가 되기 때문에 Catcus이용한 단위테스트 역시 빌드과정에 자동화되어 포함되어야할 필요가 있다.

지금부터는 대표적인 자바 빌드 도구인 ANT를 통해서 Catcus 테스트를 자동화하는 방법에 대해서 알아보도록 하자.

 먼저 디렉토리 구조를 살펴보자, 필자의 경우 다음과 같은 디렉토리 구조를 구성하였다.

사용자 삽입 이미지
*.java 파일은 src 디렉토리에 위치하였으며, 개발에 필요한 각종 jar 파일은 lib 디렉토리에 저장하였다. web.xml과 같은 config 파일은 conf 파일에 저장하였다.

 ANT로 빌드를 진행하면, *.class 파일은 ./build 디렉토리에 저장되고, ./build디렉토리에 저장된 클래스와 ./lib 디렉토리의 라이브러리 그리고 ./conf/web.xml 파일은 pack 디렉토리에서 Cactus.war라는 파일로 패키징되서 저장된다.

 다음은 작성한 ANT 스크립트이다. BUILD에서부터 WAR 파일 생성까지를 진행하고, “cactus-test” 라는 task에서 cactus 테스트를 수행하도록 설정하였다. (진하게 블록으로 표시한 부분) 빌드와 패키징 부분에 대한 설명은 생략하고 cactus 이용 ANT TASK 부분을 살펴보자. 

<project name="CactusTest" default="cactus-test" >

         <!--

       ============================================================================================

        기본 환경 정보 설정

        =============================================================================================

        -->    

        <!-- 기본 디렉토리 정보 -->

        <property name="project.name" value="Cactus"/>

        <property name="lib" value="./lib"/>

        <property name="src" value="./src"/>

        <property name="build" value="./build"/>

        <property name="packaging" value="./pack"/>

        <property name="conf" value="./conf"/>

 

        <property name="cactus.home" value="D:\dev\lib\jakarta-cactus-13-1.7.2"/>

        <property name="cactus.testlog" value="c:\temp\test-report"/>

        <property name="tomcat.home" value="D:\dev\apache-tomcat-5.5.23\"/>

 

        <!-- jar 파일 경로 -->

        <property name="cactus.jar" value="${cactus.home}/lib/cactus-1.7.2.jar"/>

        <property name="cactus-ant.jar" value="${cactus.home}/lib/cactus-ant-1.7.2.jar"/>

        <property name="commons-httpclient.jar" value="${cactus.home}/lib/commons-httpclient-2.0.2.jar"/>

        <property name="commons-logging.jar" value="${cactus.home}/lib/commons-logging-1.0.4.jar"/>

        <property name="aspectjrt.jar" value="${cactus.home}/lib/aspectjrt-1.2.1.jar"/>

        <property name="cargo.jar" value="${cactus.home}/lib/cargo-0.5.jar"/>

        <property name="servletapi.jar" value="${lib}/servletapi-2.3.jar"/>

        <property name="junit.jar" value="${lib}/junit-3.8.1.jar"/>

 

        <!-- class path 설정 -->

        <path id="cactus.classpath">

            <pathelement location="${cactus.jar}"/>

            <pathelement location="${cactus-ant.jar}"/>

            <pathelement location="${commons-httpclient.jar}"/>

               <pathelement location="${commons-logging.jar}"/>

               <pathelement location="${aspectjrt.jar}"/>

               <pathelement location="${cargo.jar}"/>

               <pathelement location="${junit.jar}"/>

        </path>

        <!--

        =============================================================================================

        Task 정의

        =============================================================================================

        -->    

        <!-- Cactus task 정의 -->

        <taskdef resource="cactus.tasks" classpathref="cactus.classpath"/>

       

        <!-- Clean -->

        <target name="clean">

               <delete dir="${build}"/>

               <mkdir dir="${build}" />

               <mkdir dir="${packaging}" />

        </target>

        <!--

        =============================================================================================

        컴파일

        =============================================================================================

        -->    

        <!-- 소스 컴파일 -->

        <target name="compile"  >

               <javac srcdir="${src}" destdir="${build}">

                       <classpath>

                              <path refid="cactus.classpath"/>

                              <pathelement location="${servletapi.jar}"/>

                       </classpath>

               </javac>

        </target>

        <!--

        =============================================================================================

        패키징

        ${build} 생성된 클래스들과, ${conf} 있는 web.xml 설정 정보를 모아서 하나의 WAR파일로 패키징 한다.

        =============================================================================================

        -->    

        <!-- WAR 패키징 -->

        <target name="packaging" depends="compile" >

               <war warfile="${packaging}/${project.name}.war"      webxml="${conf}/web.xml" >

                       <classes dir="${build}" />

                       <lib dir="${lib}"/>

               </war>

        </target>

       

        <!--

        =============================================================================================

        배포

        LOCAL Machine으로 배포하는 스크립트로 tomcat /webapps 디렉토리에 war파일을 복사한다.

        =============================================================================================

        -->    

        <!-- 배포 -->

        <target name="deploy" depends="packaging" >

               <copy file="${packaging}/${project.name}.war" todir="${tomcat.home}/webapps"/>

        </target>

       

        <!--

        =============================================================================================

        테스트

        =============================================================================================

        -->           

        <!-- Cactus 테스트 -->

        <target name="cactus-test">

                <!-- Run the tests -->

                 <cactus  warfile="${packaging}/${project.name}.war" fork="yes"

                       printsummary="yes"

                     failureproperty="tests.failed"> 

                       <classpath>

                              <path refid="cactus.classpath"/>

                              <pathelement location="${servletapi.jar}"/>

                              <pathelement location="${build}"/>

                       </classpath>

                   <containerset>

                       <!--

                       <tomcat5x dir="D:\dev\apache-tomcat-5.5.23" port="8080"      />

                               -->

                       <generic name="local tomcat" port="8080">

                            <startup target="dummy"/>

                            <shutdown target="dummy"/>

                       </generic>

                      

                   </containerset>

 

                   <formatter type="brief" usefile="false"/>

                   <formatter type="xml"/>

                   <batchtest todir="${cactus.testlog}">

                     <fileset dir="./src">

                       <include name="**/Test*.java"/>

                     </fileset>

                   </batchtest>

                 </cactus>

                 <!-- JUnit(cactus) 테스트 리포트 생성 -->

                 <junitreport todir="${cactus.testlog}">

                       <fileset dir="${cactus.testlog}" includes="TEST*.xml"/>

                       <report todir="${cactus.testlog}" format="frames"/>

                 </junitreport>

                      

                 <fail if="tests.failed"> cactus Test failed</fail>

        </target>

        <target name="dummy">

        </target>

       

       

</project>

                      

<Cactus 실행용 ANT 스크립트 >

 l        cactus 용 테스크 정의하기

먼저 ant cactus 테스크를 추가하자.

CLASSPATH cactus에 필요한 클래스들을 추가한후 taskdef이용하여 cactus.tasks resource로 정의하면 cactus 관련된 task들을 정의할 수 있다. (cactus.tasks는 실제로 cactus에 관련된 jar파일 내에 존재한다.)

        <!-- class path 설정 -->

        <path id="cactus.classpath">

            <pathelement location="${cactus.jar}"/>

            <pathelement location="${cactus-ant.jar}"/>

            <pathelement location="${commons-httpclient.jar}"/>

               <pathelement location="${commons-logging.jar}"/>

               <pathelement location="${aspectjrt.jar}"/>

               <pathelement location="${cargo.jar}"/>

               <pathelement location="${junit.jar}"/>

        </path>

      

        <taskdef resource="cactus.tasks" classpathref="cactus.classpath"/>

    

이제는 cactus 관련 테스크들을 사용할 수 있다.

 l        cactus 테스크 사용

실제로 cactus 테스크를 사용해야 하는데, 테스크의 내용을 나눠보면 크게, 테스트할 WAR파일 설정, CLASSPATH 설정,테스트용 서버 정보 설정, 테스트할 유닛들 지정 및 로그 정리 절차로 나눠볼 수 있다.

 

<cactus  warfile="${packaging}/${project.name}.war" fork="yes"

printsummary="yes" failureproperty="tests.failed">

 

warfile 속성에 테스트할 (서버에 배포한) war 파일을 지정하고, failureproperty에 실패값을 지정한다. 그리고 해당 target 마지막 부분에 이 failureproperty 값으로 아래와 같이 실패 처리를 한다..

<fail if="tests.failed"> cactus Test failed</fail>

만약 이 처리를 하지 않으면 cactus 단위 테스트가 실제로 실패하더라도 ant target에 대한 결과는 Successful로 처리된다.

 다음으로 cactus 테스트에서 사용할 클래스 패스를 지정하는데, cactus 관련 클래스들 이외에, 테스트에 사용된 클래스들을 사용하기 위한 lib들이 포함되어야 하며, 반드시 빌드된 테스트 클래스들을 CLASSPATH에 포함 시켜야 한다. (아래 굵게 표시한 부분)

 

<classpath>

<path refid="cactus.classpath"/>

<pathelement location="${servletapi.jar}"/>

<pathelement location="${build}"/>

</classpath>

 

cactus in-container 테스트이기 때문에 테스트할 컨테이너를 꼭 지정해야 하는데,catcus에서는 테스트할 서버를 직접 기동해서 WAR파일을 배포하는 것 까지 자동화 할 수 있다.Tomcat Orion,Resin,WebLogic까지 지원하는데 자세한 내용은 cactus의 문서를 참고하도록 하고 필자는 generic이란 element이용하여, 단순하게, 테스트할 서버의 URL PORT만 지정하였다. (테스트할 서버는 서블릿과 테스트 서블릿이 배포된 서버를 의미한다.)

<containerset>

<generic name="local tomcat" port="8080">

      <startup target="dummy"/>

      <shutdown target="dummy"/>

</generic>

</containerset>

:

<target name="dummy">

</target>

 

그리고 두개의 element 를 지정해야 하는데, startupshutdown 엘리먼트이다.

이 엘리먼트는 서버가 기동되어 있지 않은 경우 실행되어 서버를 기동시키고 테스트가 끝난후에 서버를 자동으로 내리는 역할을 하는 “target”을 지정해야 한다. (필수 element 이다.)

필자는 서버의 기동과 정지를 ANT 내에서 처리 하지 않고 직접 처리하였기 때문에, “dummy”라는 아무 작업도 하지 않는 target을 정의하여 지정하였다.

다음으로 Unit 테스트에 대한 로그를 저장하는 설정을 진행한다. <formatter> 라는 element를 사용하는데 Cactus JUnit의 확장이기 때문에 JUnit formatter element를 지원한다.

여기서 사용한 formatter type 속성은 두가지로 brief xml 을 사용하였다.

Brief는 테스트의 실패이유를 대략적으로 출력해주는 속성이고 xml은 테스테에 대한 각종 정보(통계,프로퍼티등등)을 상세하게 저장해주는 속성이다.

brief 값은 usefile=”false” 로 설정하여, stdout(화면)으로 출력하도록 하였고, xml usefile을 설정하지 않아서 파일로 저장되도록 하였다. 파일 경로는 다음 설명할 <batchtest> element에서 지정되는 todir 디렉토리에 저장되게 된다.

 

<formatter type="brief" usefile="false"/>

<formatter type="xml"/>

 

이제 실제로 테스트할 테스트 클래스들을 선택해야 하는데 한꺼번에 지정하기 위해서 fileset element이용하여, Test*.java 로 된 모든 테스트 클래스들을 수행하도록 하였고, 로그 파일은 todir로 정의된 ${cactus.testlog} 디렉토리에 저장되도록 설정하였다.

 

<batchtest todir="${cactus.testlog}">

      <fileset dir="./src">

        <include name="**/Test*.java"/>

      </fileset>

</batchtest>

 

cactus 테스트를 수행하기 위한 준비가 완료되었고 여기까지 설정하면 실제로 테스트를 수행할 수 있다.

 

여기에 하나 덧붙여서 설명하면, 테스트 결과는 formatter에서 type=”xml”로 설정한 부분이 XML파일로 저장된다. 그러나 이 파일을 읽기가 쉽지 않기 때문에, xml 파일을 이용하여 보기 쉬운 HTML로 테스트 결과를 생성해주는데 junitreport element를 사용할 수 있다.

<junitreport todir="${cactus.testlog}">

       <fileset dir="${cactus.testlog}" includes="TEST*.xml"/>

       <report todir="${cactus.testlog}" format="frames"/>

 </junitreport>

아래는 <junitreport> 이용하여 테스트 결과를 HTML로 생성한 결과이다.

사용자 삽입 이미지
<그림 junitreport이용하여 Cactus 테스트 결과를 HTML로 생성한 결과 >

자아, 이제 cactus이용한 테스트와 리포트 생성까지 모두 살펴보았다.

다소 복잡하기는 하지만 JUnitEE보다 훨씬 더 정교한 J2EE 컴포넌트 테스트를 지원하고, ANT 스크립트 역시 개발 빌드 과정에서 필요한 부분에 약간만 더 해진것이기 때문에 정교한J2EE 컴포넌트 테스트를 진행하기 위해서는 Cactus를 사용하는 것을 권장한다.

 

 

 


JCS,JPF,JCX등에 대한 테스트 방법
http://dev2dev.bea.com/pub/a/2004/12/eckels_BP.html

아래는 JWebUnit이다. HttpUnit의 확장판인데. 특히나
assert 메서드들이 흥미롭다.
예를 들어
assertTextPresent("Hello World!");
assertTextInElement("attributeOne", pretendObject.getAttributeOne());
위의 둘처럼 response HTML을 모두 무식(?)하게 테스트 하는 것이 아니라 어떤 Text가 있는지, 내지는 Element내에 있는 Text를 검색함으로써 좀더 resonable한 테스트가 가능하다.
통채로 HttpResponse를 테스트 한다면, 디자인이 (CSS,Javascript,HTML등등)이 변경이 되면 테스트도 깨질 수 있는데, 특정 텍스트 검색등은 실제 비지니스 로직과 관련이 되기 때문에 이 데이타만 비교한다면, 디자인에 무관하게 View단 (JSP,Servlet)에 대한 테스트가 가능할것 같다.
물론 서버쪽과의 통신은 Catcus나, JUnitEE등을 사용해야겠지만..

강좌 문서 : http://today.java.net/pub/a/today/2007/04/12/embedded-integration-testing-of-web-applications.html
JWebTest URL : http://jwebunit.sourceforge.net/articles.html
한글 문서 : http://tong.nate.com/ggypsy/20308320

단위 테스트 관련 자료를 찾아보니, Catcus는 국내 자료는 거의 없고, 생각보다 JWebUnit에 대한 자료는 많이 찾을 수 있었다. 단위 테스트에서 실제 UI단까지 테스트 하는것이 옳은지는 모르겠지만, 많이들 사용하는것을 봐서는 한번쯤 주먹해볼 필요가 있을듯.

'ALM > Test Automation' 카테고리의 다른 글

Cactus 실행용 ANT 스크립트  (0) 2007.09.13
Cactus 빌드 스크립트 샘플  (0) 2007.09.12
Unit Testing WebLogic Workshop 8.1 Applications & JWebUnit  (0) 2007.08.27
JUnitEE vs Catcus  (0) 2007.08.27
DBUnit 예제  (1) 2007.08.27
단위 성능 테스트  (0) 2007.08.24

JUnitEE vs Catcus

ALM/Test Automation | 2007.08.27 22:45 | Posted by 조대협
JUnitEE is a much simpler framework than Cactus, and provides a mechanism with which to invoke regular JUnit tests inside the container. You write your JUnit tests as normal and deploy them along with your application. You then (from your browser) request a predefined Servlet and tell it which JUnit tests to run. The results are then presented to you in a readble HTML form.

Cactus on the other hand is a much more complex beast and provides you with a ready-made set of classes from which you can write tests for Servlets, JSPs, taglibs and EJBs.

With JUnitEE, writing standard JUnit tests doesn't provide you with easy access to the environment, meaning that you can't easily run assertions on things like the current ServletRequest, response, etc. The classes (test cases) that you extend in Cactus provide you with wrappers to the actual objects that are currently "live" within the server. In other words, you can actually get access to things like the current ServletRequest and run assertions against it.

<shameless plug>
The thing that I don't like about Cactus is its support for testing JSP custom tags as you have to test them by writing the code to mimic the way that the JSP container uses them. If you need to test custom tags, check out TagUnit for an alternative that allows you to write tests within JSP.
</shameless plug>

Cheers
Simon
==
정리하자면, JUnitEE는 JUnit테스트를 단순하게, Server container안에서 동작하게 해주는것이고, Catcus는 JSP,TagLib,Servlet,EJB에 대한 좀더 구체적인 테스트 프레임웍을 제공한다. (HTTP로 Request를 넣어서 Response를 받는것은 HttpUnit을 사용해야 한다.)

'ALM > Test Automation' 카테고리의 다른 글

Cactus 빌드 스크립트 샘플  (0) 2007.09.12
Unit Testing WebLogic Workshop 8.1 Applications & JWebUnit  (0) 2007.08.27
JUnitEE vs Catcus  (0) 2007.08.27
DBUnit 예제  (1) 2007.08.27
단위 성능 테스트  (0) 2007.08.24
단위 테스트 방법  (0) 2007.08.24