計算機學習積累

          ----轉載有理,轉載是想研究,想研究才會看,看了才會有感想,轉載后我有時會寫一些自己的感受
          數據加載中……

          EasyMock的簡單使用(摘)


          xp開發的一個利器--EasyMock。
          EasyMock是一種
          動態生成模仿對象以便應用于單元測試的工具,有了它可擺脫容器進行單元測試了。
          它的使用很簡單,下面一個簡單登陸驗證的例子:
          public ? class ?LoginServlet? extends ?HttpServlet?{


          protected ? void ?doPost(HttpServletRequest?request,?HttpServletResponse?response)? throws
          ?ServletException,?IOException?{

          String?username?
          = ?request.getParameter( " username "
          );

          String?password?
          = ?request.getParameter( " password "
          );

          // ?check?username?&?password:


          if ( " admin " .equals(username)? && ? " 123456 " .equals(password))?{
          ?????ServletContext?context?
          =
          ?getServletContext();
          ?????RequestDispatcher?dispatcher?
          = ?context.getNamedDispatcher( " dispatcher "
          );
          ?????dispatcher.forward(request,?response);
          }
          else
          ?{
          ?????
          throw ? new ?RuntimeException( " Login?failed. "
          );
          }
          }
          }

          這個 Servlet 實現簡單的用戶驗證的功能,若用戶名和口令匹配“ admin ”和“ 123456 ”,則請求被轉發到指定的 dispatcher 上,否則,直接拋出 RuntimeException

          為了測試 doPost() 方法,我們需要模擬 HttpServletRequest ServletContext RequestDispatcher 對象,以便脫離 J2EE 容器來測試這個 Servlet

          我們建立 TestCase ,名為 LoginServletTest

          public ? class ?LoginServletTest? extends ?TestCase?{

          }

          我們首先測試當用戶名和口令驗證失敗的情形,演示如何使用EasyMock來模擬HttpServletRequest對象:

          public ? void ?testLoginFailed()? throws
          ?Exception?{

          MockControl?mc?
          = ?MockControl.createControl(HttpServletRequest. class
          );

          HttpServletRequest?request?
          =
          ?(HttpServletRequest)mc.getMock();

          // ?set?Mock?Object?behavior:


          request.getParameter(
          " username " );

          mc.setReturnValue(
          " admin " ,? 1
          );

          request.getParameter(
          " password "
          );

          mc.setReturnValue(
          " 1234 " ,? 1
          );

          // ?ok,?all?behaviors?are?set!


          mc.replay();

          // ?now?start?test:

          LoginServlet?servlet?
          = ? new ?LoginServlet();

          try
          ?{

          servlet.doPost(request,?
          null
          );

          fail(
          " Not?caught?exception! "
          );

          }

          catch
          (RuntimeException?re)?{

          assertEquals(
          " Login?failed. "
          ,?re.getMessage());

          }

          // ?verify:


          mc.verify();

          }

          仔細觀察測試代碼,使用 EasyMock 來創建一個 Mock 對象需要首先創建一個 MockControl
          MockControl?mc? = ?MockControl.createControl(HttpServletRequest. class );

          然后,即可獲得 MockControl 創建的 Mock 對象:
          HttpServletRequest?request? = ?(HttpServletRequest)mc.getMock();

          下一步,我們需要“錄制” Mock 對象的預期行為。在 LoginServlet 中,先后調用了 request.getParameter("username") request.getParameter("password") 兩個方法,因此,需要在 MockControl 中設置這兩次調用后的指定返回值。我們期望返回的值為“ admin ”和“ 1234 ”:
          request.getParameter( " username " );? // ?期望下面的測試將調用此方法,參數為"username"
          mc.setReturnValue( " admin " ,? 1 );? // ?期望返回值為"admin",僅調用1次

          request.getParameter(
          " password " );? // ?期望下面的測試將調用此方法,參數為"?password"

          mc.setReturnValue(
          " 1234 " ,? 1 );? // ?期望返回值為"1234",僅調用1次
          緊接著,調用 mc.replay() ,表示 Mock 對象“錄制”完畢,可以開始按照我們設定的方式運行,我們對 LoginServlet 進行測試,并預期會產生一個 RuntimeException
          LoginServlet?servlet? = ? new ?LoginServlet();

          try
          ?{

          servlet.doPost(request,?
          null
          );

          fail(
          " Not?caught?exception! "
          );

          }

          catch
          (RuntimeException?re)?{

          assertEquals(
          " Login?failed. "
          ,?re.getMessage());

          }

          由于本次測試的目的是檢查當用戶名和口令驗證失敗后, LoginServlet 是否會拋出 RuntimeException ,因此, response 對象對測試沒有影響,我們不需要模擬它,僅僅傳入 null 即可。

          最后,調用 mc.verify() 檢查 Mock 對象是否按照預期的方法調用正常運行了。

          運行 JUnit ,測試通過!表示我們的 Mock 對象正確工作了!
          ? 下一步,我們來測試當用戶名和口令匹配時,LoginServlet應當把請求轉發給指定的RequestDispatcher。在這個測試用例中,我們除了需要HttpServletRequest Mock對象外,還需要模擬ServletContextRequestDispatcher對象:


          MockControl?requestCtrl? = ?MockControl.createControl(HttpServletRequest. class );

          HttpServletRequest?requestObj?
          =
          ?(HttpServletRequest)requestCtrl.getMock();

          MockControl?contextCtrl?
          = ?MockControl.createControl(ServletContext. class
          );

          final ?ServletContext?contextObj? =
          ?(ServletContext)contextCtrl.getMock();

          MockControl?dispatcherCtrl?
          = ?MockControl.createControl(RequestDispatcher. class
          );

          RequestDispatcher?dispatcherObj?
          =
          ?(RequestDispatcher)dispatcherCtrl.getMock();

          按照doPost()的語句順序,我們設定Mock對象指定的行為:

          requestObj.getParameter(
          " username "
          );

          requestCtrl.setReturnValue(
          " admin " ,? 1
          );

          requestObj.getParameter(
          " password "
          );

          requestCtrl.setReturnValue(
          " 123456 " ,? 1
          );

          contextObj.getNamedDispatcher(
          " dispatcher "
          );

          contextCtrl.setReturnValue(dispatcherObj,?
          1
          );

          dispatcherObj.forward(requestObj,?
          null
          );

          dispatcherCtrl.setVoidCallable(
          1
          );

          requestCtrl.replay();

          contextCtrl.replay();

          dispatcherCtrl.replay();

          然后,測試 doPost() 方法,這里,為了讓 getServletContext() 方法返回我們創建的 ServletContext Mock 對象,我們定義一個匿名類并覆寫 getServletContext() 方法:
          LoginServlet?servlet? = ? new ?LoginServlet()?{

          public
          ?ServletContext?getServletContext()?{

          return
          ?contextObj;

          }

          };

          servlet.doPost(requestObj,?
          null
          );

          最后,檢查所有Mock對象的狀態:

          requestCtrl.verify();

          contextCtrl.verify();

          dispatcherCtrl.verify();

          運行 JUnit ,測試通過!

          倘若 LoginServlet 的代碼有誤,例如,將 context.getNamedDispatcher("dispatcher") 誤寫為 context.getNamedDispatcher("dispatcher2") ,則測試失敗, JUnit 報告:

          junit.framework.AssertionFailedError:

          Unexpected method call getNamedDispatcher("dispatcher2"):

          getNamedDispatcher("dispatcher2"): expected: 0, actual: 1

          getNamedDispatcher("dispatcher"): expected: 1, actual: 0

          at ...

          總結:

          雖然 EasyMock 可以用來模仿依賴對象,但是,它只能動態模仿接口,無法模仿具體類。這一限制正好要求我們遵循“針對接口編程”的原則:如果不針對接口,則測試難于進行。應當把單元測試看作是運行時代碼的最好運用,如果代碼在單元測試中難于應用,則它在真實環境中也將難于應用。總之,創建盡可能容易測試的代碼就是創建高質量的代碼。

          ? 現在,easymock可以模仿類了,以下是在springside摘的:

          // 設定BookManager?MockObject
          ????????bookManagerMockControl? = ?MockClassControl.createControl(BookManager. class );
          ????????bookManagerMock?
          =
          ?(BookManager)?bookManagerMockControl.getMock();
          ????????controller.setBookManager(bookManagerMock);
          ???????
          // 錄制getAllBook()和getCategorys方法的期望值

          ????????bookManagerMock.getAllBook();
          ????????bookManagerMockControl.setReturnValue(
          new
          ?ArrayList());
          ????????bookManagerMockControl.replay();
          ????????
          // 執行操作

          ????????mv? = ?controller.handleRequest(request,?response);
          // 驗證結果?????????

          ????????assertModelAttributeAvailable(mv,? " books " );


          posted on 2007-03-02 09:13 freebird 閱讀(554) 評論(0)  編輯  收藏 所屬分類: java

          主站蜘蛛池模板: 阿拉善右旗| 长春市| 克什克腾旗| 荆门市| 白水县| 宁晋县| 莱西市| 全州县| 邯郸市| 门头沟区| 谢通门县| 申扎县| 郴州市| 磴口县| 逊克县| 仲巴县| 德昌县| 西乌珠穆沁旗| 黄大仙区| 嵊泗县| 新巴尔虎左旗| 辽宁省| 神农架林区| 交口县| 虞城县| 天全县| 克东县| 汨罗市| 清镇市| 东城区| 连山| 台北县| 克东县| 土默特左旗| 汶上县| 鲁山县| 南平市| 新巴尔虎右旗| 洪江市| 洪泽县| 塘沽区|