StrutsTestCase 使用的一點感悟

來源:互聯網
上載者:User

StrutsTestCase用於對基於Struts架構的Web應用進行單元測試,它可以用來測試ActionForm,Action的Execute方法,Action Forward, 及轉向後的JSP是否正確。一個典型的Case代碼如下: 

        setRequestPathInfo("/DriveBus");
        addRequestParameter("driver", "tang");
        actionPerform();
        verifyForward("success");

        就這樣的短短几行代碼,在實際運行過程中卻遇到很多問題。 1. junit.framework.AssertionFailedError: Error initializing action servlet: Unable to find /WEB-INF/web.xml.  TestCase is running from D:ideeclipse3.0.1workspaceztest directory.  Context directory has not been set.  Try calling setContextDirectory() with a relative or absolute path.  /WEB-INF/web.xml must be found under the context directory, the directory the test case is running from, or in the classpath.

 這個錯誤原因是沒有找到web-inf/web.xml所在的目錄。一般被測代碼和測試的代碼不是在一個工程下的。如的結構所示:  

 projects
   |-myWeb
   |   |-src
   |   |-WEB-INF
   |      |-classes
   |      |-lib
   |   
   |      | struts-confg.xml
   |      | web.xml
   |   
   |-test
       |-src

 

test工程包含所有用來測試myWeb工程的TestCase,這時候就需要覆寫MockStrutsTestCase裡的setup()方法:protected void setUp() throws Exception
    ...{
        // TODO Auto-generated method stub
        super.setUp();
        setContextDirectory(new File("../myWeb"));
    }

    例如可以用以下的句子來說明.xml的位置所在。

      

 // set the context directory to /WebRoot
        // to find the /WEB-INF/web.xml
        setContextDirectory(new File("WebRoot"));
        setConfigFile("MyFileSystem", "/WEB-INF/struts-config.xml");

SetContextDirectory()方法保證TestCase能正確找到web.xml和struts-config.xml檔案。 2。 setRequestPathInfo()用來設定頁面的form提交時執行的action,如jsp中form代碼為:<FORM action="DriveBus.do" method="post">,則應該寫成setRequestPathInfo("/DriveBus").注意該函數的參數:   1)DriveBus前面的左斜杠是必需的。   2)不能包含context路徑。   3)在後面加上.do是沒有問題的。 3。setRequestPathInfo()存在的問題   當調用該方法時,會調用Common中的stripActionPath()進行處理,當setRequestPathInfo()的傳入參數為“/DriveBus.do”時,會被截成“/DriveBus”,它將會設定到request的pathinfo欄位。問題就在這裡。在StrutsTestCase中,對容器內的request進行了類比,用HttpServletRequestSimulator代替真正的HttpServletRequest。對於部署在容器裡的應用,如下函數的輸出分別為:  request.getPathInfo()    null
    request.getRequestURI()     /myWeb/DriveBus.do
    request.getRequestURL()     http://localhost:8080/myWeb/DriveBus.do
    request.getServletPath()    /DriveBus.do

  而類比的request得出的輸出為: request.getPathInfo()    /DriveBus
    request.getRequestURI()     null
    request.getRequestURL()    null
    request.getServletPath()     null

   可 見,HttpServletRequestSimulator並沒有能夠很好地類比request,當被測程式中調用了 request.getPathInfo()以外的方法時,測試很可能不會通過(拋NullPointerException異常),或者會出現錯誤的測 試結果。 
這個問題我自己就是受害者。
請看如下代碼:

ublic void testDownloadFileSuccess() ...{
        setRequestPathInfo("/file");

        HttpServletRequestSimulator requestSimulator = new HttpServletRequestSimulator(
                context);

        requestSimulator.setRequestURI("/MyFileSystem/do/file");
        requestSimulator
                .setRequestURL("http://localhost:8080/MyFileSystem/do/file");
        requestSimulator.setServletPath("/do");
        requestSimulator.setContextPath("/MyFileSystem");
        requestSimulator.setQueryString("fName=/dlf/bootfont.bin");

        addRequestParameter("dirmapping", "");
        addRequestParameter("filebase", "c:/");
        addRequestParameter("tempDir",
                "c:/java/tomcat 5.0/webapps/MyFileSystem/");

        actionPerform();
        
        /**//*//assertEquals("servletPath","/do");
        assertEquals("folder","folder");
        assertEquals("self","self");
        assertEquals("requestURI","requestURI");
        assertEquals("path","path");*/

    }

其中被我注釋掉的代碼是這個測試通過的斷言。這個不知道是我在初始化

  HttpServletRequestSimulator requestSimulator = new HttpServletRequestSimulator(
    context);時這個context是否錯誤了。期待有人來解決一下這個類比測試的問題。4。多模組測試StrutsTestCase支援對多模組的測試,在setRequestPathInfo()中可以指定模組名稱,setRequestPathInfo(String moduleName, String pathInfo),其部分代碼如下:  this.actionPath = Common.stripActionPath(pathInfo);
        if (moduleName != null) ...{
            if (!moduleName.equals("")) ...{
                if (!moduleName.startsWith("/"))
                    moduleName = "/" + moduleName;
                if (!moduleName.endsWith("/"))
                    moduleName = moduleName + "/";
            }
            if (logger.isDebugEnabled()) ...{
                logger.debug("setting request attribute - name = " + Common.INCLUDE_SERVLET_PATH + ", value = " + moduleName);
            }
            this.request.setAttribute(Common.INCLUDE_SERVLET_PATH, moduleName);
        }
        this.request.setPathInfo(actionPath);
        this.requestPathSet = true;

  它將傳入的模組名名設定到request的Common.INCLUDE_SERVLET_PATH屬性,但是在verifyForwardPath()的代碼中卻有這樣一段:String moduleName = request.getServletPath() != null ? request.getServletPath() : "";
        if ((moduleName == null || moduleName.equalsIgnoreCase("")) && request.getAttribute(INCLUDE_SERVLET_PATH) != null)
            // check to see if this is a MockStrutsTestCase call
            moduleName = (String) request.getAttribute(INCLUDE_SERVLET_PATH);

     當可以取到ServletPath時,將其值作為moduleName,這個真是讓人想不通!!servletPath和模組名有什麼關係呢?  (對於URI, URL, URN的詳細說明見:http://www.ietf.org/rfc/rfc1738.txt,所以StrutsTestCase對HttpServletRequest的類比是不符合規範的) 5。contextPath這個值始終是Null 字元串 總 之,當我們使用StrutsTestCase進行測試時,需要對以上問題多加留意,當出錯時,可能會是StrutsTestCase本身的問題,必要的 話,可以對其進行源碼進行修改,以適合我們系統本身的需求。StrutsTestCase的license是 Apache Software License。 附: Apache Software License (ASL)可以相容其它任何已知的許可證。 已知的最大例外是GNU Public License (GPL) 和Lesser GNU Public License (LGPL). 重要的是ASL對合作開發相當友好,如果您不想的話,也不會強迫您發布原始碼。 Apache Software Foundation名下的德高望眾的HTTP伺服器用的是相同的許可證。 (完)

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.