• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    追求代碼質量: 測試 Struts 遺留的應用程序

    發布: 2007-5-24 22:03 | 作者: Andrew Glover | 來源: IBM | 查看: 38次 | 進入軟件測試論壇討論

    領測軟件測試網 雖然 Struts 正在慢慢退出 Web 框架的歷史舞臺,但它的遺產仍然存在,存在的形式主要是需要測試和維護的應用程序。這個月,Andrew Glover 向您介紹如何使用 JUnit 的 StrutsTestCase、DbUnit 以及在這個系列中迄今為止學到的一些工具,把以質量為中心的方法用于 Struts 上的測試(可以這么說)。

    基于 Java™ 的 Web 開發領域最近出現了豐富的競爭性技術。啟動新項目的開發人員可以在許多不同的框架之間進行選擇,包括 JavaServer Faces、Tapestry、Shale、Grails 和 Seam (只列舉眾多機靈的名稱中的幾個)。很快,我們就可以通過 JRuby 框架在 Java 編程中使用 Ruby on Rails 了!

    但就在不遠的過去,只有一個 Java Web 開發框架卓然而立。Struts 是第一個在 Java 世界掀起風暴的框架,而且多年以來,好像是如果一個項目不用 Struts 構建就沒有前途一樣。沒有 Struts 經驗的 Java 開發人員很稀少,也很不幸,就像今天的開發人員沒有聽說過 Ruby on Rails 一樣。

    提高代碼質量
    不要錯過 Andrew 的附帶 討論組 ,可以得到最迫切問題的答案。

    即使 Struts 正慢慢地從舞臺中央退去(原來的基本框架,現在叫做 Struts 1,似乎正在退出 Web 框架的歷史舞臺),但它的遺產仍然存在,既以 Shale (請參閱 參考資料)的形式存在,又以運行在世界各地的成千上萬的遺留應用程序的形式存在。因為許多企業寧愿測試和維護這些應用程序而不愿意花錢重新編寫它們,所以理解 Struts 應用程序的一些缺陷,以及如何圍繞它們進行重構,是個好主意。

    這個月,我要把以質量為核心的方法用于 Struts 應用程序的測試場景。結合現實,這個場景圍繞著最普遍的 Struts 構造:深受喜愛的 Action 類。

    1、2、3,行動!

    Struts 的革新之一就是把 Web 開發從 Servlet 移進了 Action 類。這些類包含業務邏輯,以 JavaBean 的形式(通常叫做 ActionForm)把數據傳送到 JSP。然后 JSP 處理應用程序視圖。Struts 到 MVC 的方法非常容易掌握,以至于許多開發團隊冒失地闖進去,而很少考慮與 Action 相關的長期設計和維護問題。

    測試和復雜性

    我已經發現,在開發人員的測試和代碼的復雜性之間存在強烈的相關性:沒有其中一個的地方,通常也沒有另一個。高度復雜的編碼難于測試,結果是很少有人會真正為它編寫測試。反過來,編寫測試可以降低代碼的復雜性。因為給復雜代碼編寫測試更困難,而且因為會邊走邊測試,所以會發現自己朝著更簡單的代碼構造前進。如果代碼太復雜,而且知道不得不測試它,您可能就會在測試之前對復雜性進行重構。不論如何看待,為不那么簡單的代碼編寫測試是消滅代碼復雜性的好實踐。

    雖然在那個時候(過去的自由時光。┛赡軟]人想過,但 Struts Action 類通常成為復雜性的保護所。像在老的 EJB 架構中聲名狼籍的會話 Facade 一樣,Action 類會成為特定業務過程的嚴格偽裝,或者通過直接調用 EJB,通過打開數據庫連接,或者通過調用其他高度依賴的對象。Action 類還有輸出耦合(通過 java.servlet API 包中的對象,例如 HttpServletRequestHttpServletResponse),從而極難把它們隔離出來測試。

    隔離出來測試 Action 類的困難意味著它們可以很容易變得相當復雜 —— 特別是當它們變成越來越深入地與遺留框架耦合的時候,F在我們來看這個困難在真實的遺留應用程序場景中作用的情況。

    測試挑戰

    即使最簡單的 Struts Action 類也會是個測試挑戰。例如,以清單 1 中的 execute() 方法為例;它看起來足夠簡單,可以測試,但是真的么?


    清單 1. 這個方法看起來容易測試……
    public ActionForward execute(ActionMapping mapping, ActionForm aForm,
                HttpServletRequest req, HttpServletResponse res) throws Exception {
                try{
                String newPassword = ((ChangePasswordForm)aForm).getNewPassword1();
                String username = ((ChangePasswordForm)aForm).getUsername();
                IUser user = DataAccessUtils.getDaos().getUserDao().findUserByUsername(username);
                user.digestAndSetPassword(newPassword);
                DataAccessUtils.getDaos().getUserDao().saveUser(user);
                }catch(Throwable thr){
                return findFailure(mapping, aForm, req, res);
                }
                return findSuccess(mapping, aForm, req, res);
                }
                


    圖 1. Action 類的輸出耦合

    但是,就像在圖 1 中可以看到的,在試圖隔離 ChangePasswordAction 類并檢驗 execute() 方法時,該類給出了一些有代表性的挑戰。為了有效地測試 execute() 方法,必須處理三層耦合。首先,到 Struts 自身的耦合;其次,Servlet API 代表一個障礙;最后,到業務對象包的耦合,進一步檢查業務對象包,還會有數據訪問層使用 Hibernate 和 Spring。

    每種情況一個 mock?

    即使在我編寫本文時,我還可以聽到開發人員的嘲笑者 認為我的測試問題通過明智地使用 mock 對象就能輕易解決。可以 用 mock 對象創建一級隔離,它會形成更容易的測試;但是,我要說的是,把目標對象通過 mock 排除所需要的付出級別,比起承認隔離測試困難所需要的付出,要多得多。在這種情況下,我會采用在更高層次上的測試,這級測試有時叫做集成測試。

    對于更高的復雜性,請注意 清單 1 中的代碼如何把 aForm 參數轉換成 ChangePasswordForm 對象,它是 Struts ActionForm 類型。這些 JavaBeans 有一個 validate 方法,這個方法由 Struts 在調用 Action 類的 execute() 方法之前調用。

    犯錯誤太容易了

    在清單 2 中,可以看到所有這個復雜性會在哪里發生。ChangePasswordFormvalidate() 方法的代碼片段演示了保證兩個屬性(newPassword1newPassword2)不為空并彼此相等的簡單邏輯。但是,如果 Struts 發現 errors 集合(類型為 ActionErrors)包含一些 ActionError 對象,就會沿著錯誤路徑走,例如帶著出錯消息重新顯示 Web 頁面。


    清單 2. ChangePasswordForm 的驗證邏輯
    if((newPassword1 == null) || (newPassword1.length() < 1)) {
                errors.add("newPassword1",
                new ActionError("error.changePassword.newPassword1Required"));
                }
                if((newPassword2 == null) || (newPassword2.length() < 1)) {
                errors.add("newPassword2",
                new ActionError("error.changePassword.newPassword2Required"));
                }
                if((newPassword1 != null) && (newPassword2 != null)) {
                if(!newPassword1.equals(newPassword2)) {
                errors.add(ActionErrors.GLOBAL_ERROR,
                new ActionError("error.changePassword.passwordsDontMatch"));
                }
                }
                

    清單 1清單 2 的代碼不特殊也不特定于某個領域。它是無數應用程序中都包含的簡單口令修改邏輯。如果正在測試 Struts 遺留應用程序,將不得不花些時間處理口令邏輯,但是如何用可重復的方式測試它呢?





    回頁首


    兩個測試用例

    在企圖為 清單 1(間接的是 清單 2)的代碼編寫測試之前,可能想確定實際需要測試什么。在這個具體示例中,邏輯清楚地是為了方便用戶口令的修改;所以,應當編寫至少兩個層次的測試用例:

    • 口令修改在數據正確時是否工作?
    • 如果數據不正確,口令是不是 修改?

    這些測試不會太容易只是個假設。不僅需要對付 Struts,還必須處理數據層以及數據層與數據庫暗含的耦合!在面對復雜性時,我的第一本能是尋求幫助,在這個示例中,是以 JUnit 的 StrutsTestCase 的形式。





    回頁首


    來自 StrutsTestCase 的幫助

    StrutsTestCase 是一個 JUnit 擴展,專門針對 Struts 應用程序。這個框架實際上模擬了一個 servlet 容器,這樣就能虛擬地運行和測試 Struts 應用程序,而不必在 Tomcat(舉例)中運行它了?蚣苓有一個方便的 MockStrutsTestCase 類,它擴展了 TestCase 并處理許多 Struts 配置方面(例如裝入 struts-config.xml 配置文件)。

    但是,在您認為自己完全脫離了 Struts 配置的痛苦之前,應當了解一些正確配置 MockStrutsTestCase 的事情。也就是說,需要把它指向代表 Web 應用程序的目錄,然后指向必要的 web.xml 和 struts-config.xml 文件。默認情況下,MockStrutsTestCase 掃描這些項目的類路徑;但是,要把 MockStrutsTestCase 配置成在特定環境中工作,操作很簡單,只需覆蓋一些設置并編寫一些特定的配置代碼即可。

    返回口令驗證示例,包含 ChangePasswordAction 類的項目有圖 3 所示的目錄結構:


    清單 3. 示例目錄結構
    root/
                src/
                conf/
                java/
                webapp/
                images/
                jsp/
                WEB-INF/
                test/
                

    WEB-INF 目錄包含 web.xml 和 struts-config.xml 文件,webapp 目錄代表 Web 上下文環境。知道了這些,我就如清單 4 所示配置 MockStrutsTestCase


    清單 4. MockStrutsTestCase 的定制 fixture 代碼
    public void setUp() throws Exception {
                try {
                super.setUp();
                this.setContextDirectory(new File("src/webapp/"));
                this.setServletConfigFile("src/webapp/WEB-INF/web.xml");
                this.setConfigFile(
                this.getSession().getServletContext()
                .getRealPath("WEB-INF/struts-config.xml"));
                }catch (Exception e) {
                fail("Unable to setup test");
                }
                }
                

    其他測試方式

    在某些情況下,基于 Action 類中發現的對應邏輯,可能能夠用基于 Web 的測試框架(像 JWebUnit 或 Selenium間接地 測試代碼。使用這些框架從測試設置的角度來說,確實增加了復雜性。例如,要使用 JWebUnit,必須把應用程序部署到一個運行著配置好的數據庫的 servlet 容器。把 StrutsTestCase 和 DbUnit 協同使用,可以方便測試,不必 把 war 文件部署到運行著的 servlet 容器。它還允許在 考慮應用程序的視圖方面的情況下進行測試。

    關于邏輯映射

    正確地配置了 MockStrutsTestCase 的實例后,測試 Action 類就只包含一點點邏輯映射。要調用 Action 類,需要強制 StrutsTestCase 框架通過一個路徑間接地 調用它,這是在 struts-config.xml 文件中定義的。

    例如,要強制調用 ChangePasswordAction 類,必須告訴框架使用 /changePasswordSubmit 路徑。在清單 5 中可以看到這點,清單 5 中的代碼片段來自 struts-config.xml 文件,它把 ChangePasswordAction 類映射到 /changePasswordSubmit 路徑:


    清單 5. struts-config.xml 代碼片段顯示了動作類路徑映射
    <action path="/changePasswordSubmit"
                type="com.acme.ccb.action.ChangePasswordAction"
                name="changePasswordForm" scope="request"
                input="/jsp/admin/changepassword.jsp">
                <forward name="success" path="/viewUsers.do"
                redirect="true" contextRelative="false" />
                </action>
                

    一旦某個用戶點擊了提交按鈕(舉例),Struts 就把來自 HTTP 請求的參數值映射到 ActionForm,在這個示例中,是上面的 struts-config.xml 代碼片段中(在清單 5 中)定義的 ChangePasswordForm。要模擬這個行為,在測試用例中必須有另一個邏輯映射 —— JSP 表單名稱必須映射到值。在口令修改場景中,提交了四個參數:username、currentPassword、newPassword1newPassword2 newPassword2 參數是多數 Web 頁面為了校驗新口令正確的確認信息)。





    回頁首


    成功的測試用例!

    請求路徑和參數映射好之后,編寫測試用例就成了利用 MockStrutsTestCase API 設置相關口令值的問題,如清單 6 所示。在這個測試用例中,用戶 Jane 的口令從 “admin” 改成了 “meme”。


    清單 6. 一個驗證口令修改成功的簡單測試用例
    public void testExecute() throws Exception{
                setRequestPathInfo("/changePasswordSubmit");
                addRequestParameter("username","jane");
                addRequestParameter("currentPassword","admin");
                addRequestParameter("newPassword1","meme");
                addRequestParameter("newPassword2","meme");
                actionPerform();
                verifyForward("success");
                }
                

    setRequestPathInfo() 方法配置路徑以映射到 Action 類,addRequestParameter() 方法把來自 JSP 文件的參數名稱映射到值。例如,在清單 6 中,username 參數映射到 “jane”。

    還請注意清單 6 中的最后兩行。actionPerform() 方法實際上讓 Struts 去調用對應的 Action 類。如果這個方法沒被調用,什么也不會發生。最后調用的方法 verifyForward() 是在 MockStrutsTestCase 類中找到的一個類似于斷言的方法,它驗證正確的轉發。在 Struts 中,這是一個 String,通常映射到成功或失敗狀態。(請注意,清單 5 中的 XML 定義了 “success” 轉發。)





    回頁首


    用 DbUnit 進行的可重復的成功

    這時,您可能希望工作完成 —— 畢竟已經編寫了一個企圖驗證口令修改的測試。但是還缺乏更深的驗證。確實,這個方便的框架調用了 Struts,但是代碼依賴于數據庫。如果希望能夠不止一次地運行這個測試,比如在構建過程中,就需要讓它可重復。

    由于一些特定的假設,所以 清單 6 中的測試用例不是可重復的。首先,測試用例假設在系統中已經 有一個名為 “jane” 的用戶,它的口令是 “admin”。其次,測試用例假設在某些永久存儲 中口令 “admin” 被更新成 “meme”。正如所寫的那樣,只要代碼沒有生成異常,ActionForm 成功驗證,Struts 就假定事情工作良好,測試用例也是一樣。

    現在需要的是更深層次的驗證 —— 在數據庫層次。對于應當更新口令的測試用例來說,理想情況下應當在數據庫上 執行檢查,確保那里有一個新口令。對于口令不應當修改的測試來說,需要進行驗證,真正檢驗沒有修改 口令。最后,要讓這個測試套件可重復,最好是不要 對數據完整性做任何假設。

    DbUnit 是個專門方便把數據庫放進測試狀態中已知狀態的 JUnit 擴展。使用 XML 種子文件,可以把特定數據插入到測試用例可以依靠的數據庫中。而且,使用 DbUnit API,可以容易地比較數據庫的內容和 XML 文件的內容,從而提供一個在應用程序代碼之外 校驗預期數據庫結果的機制。





    回頁首


    用 DbUnit 進行測試

    要使用 DbUnit,需要兩樣東西:

    • 通過普通 JDBC 的數據庫連接
    • 一個文件,包含需要放到數據庫中的數據

    清單 7 是一個 DbUnit 種子文件,只定義了幾樣東西:首先,有一個叫做 user 的表和另一個叫做 user_role 的表。在 user 表中定義了一個新行,并映射一些值到列(例如列 username 擁有值 “jane”)。在 user_role 中還定義了一行。請注意這個數據庫中的口令是通過 SHA 加密的。


    清單 7. 用于測試表 user 和 user_role 的 DbUnit 種子文件
    <?xml version='1.0' encoding='WINDOWS-1252'?>
                <dataset>
                <!-- user with password admin -->
                <user username="jane"
                password="d033e22ae348aeb5660fc2140aec35850c4da997"
                name="Jane Admin"
                date_created="2003-8-14 10:10:10"
                email="jane@elsewhere.org"/>
                <user_role username="jane" rolename="ADMIN"/>
                </dataset>
                

    有了這個文件,就可以利用 DbUnit 插入數據、更新數據庫來反映數據,甚至刪除數據。數據庫修改邏輯包含在 DbUnit 的 DatabaseOperation 類中。在這個示例中,只是通過 清單 4 中定義的 MockStrutsTestCase 類型的 setUp() 方法中的一些增強的 fixture 邏輯中的 CLEAN_INSERT 標志來保證干凈的數據集。例如,在清單 8 中,定義了三個方法,分別利用 DbUnit API 把 dbunit-user-seed.xml 文件的內容插入數據庫。


    清單 8. 定制的 DbUnit fixture 邏輯
    private void executeSetUpOperation() throws Exception{
                final IDatabaseConnection connection = this.getConnection();
                try{
                DatabaseOperation.CLEAN_INSERT.execute(connection, this.getDataSet());
                }finally{
                connection.close();
                }
                }
                private IDataSet getDataSet() throws IOException, DataSetException {
                return new FlatXmlDataSet(new File("test/conf/dbunit-user-seed.xml"));
                }
                private IDatabaseConnection getConnection() throws ClassNotFoundException, SQLException {
                final Class driverClass = Class.forName("org.gjt.mm.mysql.Driver");
                final Connection jdbcConnection = DriverManager.
                getConnection("jdbc:mysql://localhost/ccb01",
                "9043", "43xli");
                return new DatabaseConnection(jdbcConnection);
                }
                

    清單 8 中定義的 executeSetUpOperation() 方法將在前面的 清單 4 中定義的 setUp() 方法中調用。這個方法再調用清單 8 中的另兩個方法:getDataSet() 把 XML 轉換成 DbUnit 的 IDataSet 類型,getConnection() 則返回包裝成 DbUnit 的 IDatabaseConnection 類型的數據庫連接。





    回頁首


    更好的測試用例

    配置好 DbUnit 后,剩下的就只有改進 清單 6 的測試用例,驗證數據庫中的一切 OK。然后,添加驗證其他問題場景的其余測試用例。

    要確認數據庫中的口令更新,可以使用 DbUnit 的查詢 API,它幫助比較數據庫的結果與靜態定義的 XML 文件,例如清單 9 中定義的那個。請注意這個文件沒有列出 user 表中的所有列 —— 實際上,它只列出了兩個:usernamepassword。


    清單 9. 比較測試 XML 文件
    <?xml version='1.0' encoding='WINDOWS-1252'?>
                <dataset>
                <user username="jane"
                password="58117e24e4d0b8a958146c9eaa28336184f4d491"/>
                </dataset>
                

    DbUnit 的查詢 API 足夠靈活,可以幫助過濾掉沒有意義的值,在這個示例中就是 usernamepassword 之外的值。同樣,在清單 10 中,verifyPassword() 方法用 DbUnit 的 createQueryTable() 方法構建 ITable 類型,以與清單 9 中定義的 XML 進行比較:


    清單 10. 使用 DbUnit 查詢 API 的 verifyPassword 方法
    private void verifyPassword(String fileName) throws Exception{
                final IDataSet expectedDataSet = new FlatXmlDataSet(
                new File(fileName));
                final ITable defJoinData = this.getConnection().
                createQueryTable("TestResult",
                "select user.username, user.password " +
                "from user where user.username=\"jane\"");
                final ITable defTable = expectedDataSet.getTable("user");
                Assertion.assertEquals(defJoinData, defTable);
                }
                

    Assertion 類型是 DbUnit 定義的定制類,可以進行特定于數據庫結果集的額外斷言。還請注意 verifyPassword() 接受一個文件路徑,這意味著我可以定義多個期望的數據集(一個用于修改的口令,一個用于相同的口令)。





    回頁首


    反復測試 Struts

    綜合起來,現在有了一個可以完成以下工作的測試用例:

    1. 通過 DbUnit 填充數據庫
    2. 配置 Struts
    3. 間接地調用 ChangePasswordActionChangePasswordForm
    4. 關聯參數值
    5. 驗證成功轉發
    6. 驗證數據庫內容

    從清單 11 可以看出,ChangePasswordAction 測試用例只通過 testExecute 測試處理一個正常場景:


    清單 11. ChangePasswordAction 測試用例
    package test.com.acme.ccb.action;
                import java.io.File;
                import java.io.IOException;
                import java.sql.Connection;
                import java.sql.DriverManager;
                import java.sql.SQLException;
                import org.dbunit.Assertion;
                import org.dbunit.database.DatabaseConnection;
                import org.dbunit.database.IDatabaseConnection;
                import org.dbunit.dataset.DataSetException;
                import org.dbunit.dataset.IDataSet;
                import org.dbunit.dataset.ITable;
                import org.dbunit.dataset.xml.FlatXmlDataSet;
                import org.dbunit.operation.DatabaseOperation;
                import servletunit.struts.MockStrutsTestCase;
                public class ChangePasswordActionTest extends MockStrutsTestCase {
                public ChangePasswordActionTest(String arg0) {
                super(arg0);
                }
                public void setUp() throws Exception {
                try {
                super.setUp();
                this.executeSetUpOperation();
                this.setContextDirectory(new File("src/webapp/"));
                this.setServletConfigFile("src/webapp/WEB-INF/web.xml");
                this.setConfigFile(
                this.getSession().getServletContext()
                .getRealPath("WEB-INF/struts-config.xml"));
                } catch (Exception e) {
                fail("Unable to setup test");
                }
                }
                public void testExecute() throws Exception{
                setRequestPathInfo("/changePasswordSubmit");
                addRequestParameter("username","jane");
                addRequestParameter("currentPassword","admin");
                addRequestParameter("newPassword1","meme");
                addRequestParameter("newPassword2","meme");
                actionPerform();
                verifyForward("success");
                verifyPassword("test/conf/dbunit-expect-user.xml");
                }
                private void executeSetUpOperation() throws Exception{
                final IDatabaseConnection connection = this.getConnection();
                try{
                DatabaseOperation.CLEAN_INSERT.execute(connection, this.getDataSet());
                }finally{
                connection.close();
                }
                }
                private IDataSet getDataSet() throws IOException, DataSetException {
                return new FlatXmlDataSet(new File("test/conf/dbunit-user-seed.xml"));
                }
                private IDatabaseConnection getConnection() throws ClassNotFoundException, SQLException {
                final Class driverClass = Class.forName("org.gjt.mm.mysql.Driver");
                final Connection jdbcConnection = DriverManager.
                getConnection("jdbc:mysql://localhost/ccb01",
                "9043", "43xli");
                return new DatabaseConnection(jdbcConnection);
                }
                private void verifyPassword(String fileName) throws Exception{
                final IDataSet expectedDataSet = new FlatXmlDataSet(
                new File(fileName));
                final ITable defJoinData = this.getConnection().
                createQueryTable("TestResult",
                "select user.username, user.password " +
                "from user where user.username=\"jane\"");
                final ITable defTable = expectedDataSet.getTable("user");
                Assertion.assertEquals(defJoinData, defTable);
                }
                }
                

    只多一個測試……

    請注意這個測試用例沒有測試邊界用例,例如:如果兩個口令字段(newPassword1newPassword2())不匹配。謝天謝地,一旦設置好了,添加另一個測試用例并不難。在清單 12 中,驗證了如果兩個值不匹配,就生成 ActionError,用戶 “jane” 口令在數據庫中的值保持不變。


    清單 12. 添加新測試
    public void testExecuteWithErrors() throws Exception{
                setRequestPathInfo("/changePasswordSubmit");
                addRequestParameter("username","jane");
                addRequestParameter("currentPassword","admin");
                addRequestParameter("newPassword1","meme");
                addRequestParameter("newPassword2","emem");
                actionPerform();
                verifyActionErrors(
                new String[]{"error.changePassword.passwordsDontMatch"});
                verifyPassword("test/conf/dbunit-expect-user-same.xml");
                }
                

    在清單 12 中,我驗證了 清單 2 中的邏輯正確地捕捉到了口令值不匹配的情況。MockStrutsTestCase 類包含一個方便方法可以斷言錯誤條件,這個方法是 verifyActionErrors(),在這個方法中,錯誤 String 被傳遞進來進行驗證。還請注意,數據庫被檢查,這次是根據另一個包含相同值的文件(在這個示例中,username “jane” 有一個未加密的 password “admin”)。





    回頁首


    Struts 的集成測試

    多數 Struts 應用程序不會 很快消失,所以重要的是知道如何在重寫之前用開發人員測試構建一定層次的保證。這個月,我介紹了在測試 Struts 遺留應用程序時的一些挑戰,并介紹了如何用 StrutsTestCase 和 DbUnit 處理它們。

    StrutsTestCase 只要配置正確就會處理 Struts 的工作,而 DbUnit 處理與數據庫有關的代碼的工作。一起使用這兩個框架,可以在 Struts 應用程序上進行集成級別的測試,而不用通過更高層次的框架(例如 JWebUnit 或 Selenium)模擬瀏覽器(也是一個值得采用的方法,但是生成的結果非常不同。)

    Struts 應用程序對測試來說 具有挑戰性的,并且沒有解決的方法。這個困難是 Struts 框架被更加創新的框架所掩蓋的原因之一,特別是那些解決了測試容易問題的框架。另一方面,就像我在這里介紹的,測試 Struts 可能的 —— 只是需要費些力氣。

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>