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伺服器用的是相同的許可證。 (完) |