国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

PL/SQL構建代碼分析工具之從測試開始

2024-07-21 02:33:31
字體:
來源:轉載
供稿:網友
    Feuerstein 的“構建代碼分析工具”系列的第 2 部分    在本系列的 第一篇文章中,我決定構建一個可以對代碼進行質量檢查的實用工具:非凡是識別 PL/SQL 程序包中具有歧義或者潛在歧義的超載問題。     此外,我還識別數據源(ALL_ARGUMENTS 數據字典視圖)和代碼(DBMS_DESCRIBE 程序包),以幫助構建實用工具。下一步要做什么呢?    坦率地說,我自然傾向于打開我所喜愛的集成開發環境 (IDE) 并開始動指如飛地編寫代碼,投入激動人心的創作之中。我希望在工作時思考并得出結論,不斷地應對挑戰,使工作成果運行起來,然后對其進行微調。    這種方法有積極的方面(您當然不會有過度設計的風險),但也有很多缺點。首先,假如我所使用的構建方法是直通式構造非線性系統 — 常被親切地稱為 HRCLS 或 Hercules(一種非常輕型的方法論),我最終不會僅是微調代碼。絕對不會,在我將范圍縮小到最終目的、目標和實質內容時,我最終將會以重寫整個程序 — 一次、兩次或三次。但是,盡管可以激動地看到,經過自己的努力,實用工具成形、進步并改觀,但這會浪費很多的時間。    對于 Codecheck,我會忍住最初的誘惑。我不會在項目開始的頭 60 秒內就編寫代碼,而是做一個簡單的聲明:我保證使我編寫的代碼適用于一個全面的測試計劃。    這與避免 Hercules 綜合癥有什么必然的關系呢?讓我們來考慮這種保證的含義:    我將制訂一個測試計劃,它非常全面,精心策劃了數十個(甚至可能有 100 個之多)測試方案,包括參數的數量、各種數據類型的結合以及缺省值的有無。    我要設計、構建和運行測試,這些測試可確定我的代碼是否滿足測試計劃的要求:換言之,設計、構建和運行涵蓋我的全部測試方案的測試。    天哪,這聽起來確實很有道理,不是嗎?我的意思是,誰會一直做所有的這些事情?況且,我們都知道這樣的事實:我們之中很少有人實際上會花時間,或在手邊有必備的工具去做全面的測試。實際上我認為,世界上至少百分之九十的軟件開發人員和開發團隊(包括我自己)遠遠不會完全按上述保證去做。    對我來說,在開發初始時我表明要執著地進行測試,我發現這一點促使我實現了 Codecheck.    定義范圍,做出假設    在開發一項測試策略并構造測試之前,我需要確定項目的使用范圍。用戶群通常確定(并經常更改)項目的使用范圍。對于 Codecheck 以及我制作的很多其他實用工具,您,開發人員,是我的用戶,但我仍然需要確定使用范圍,把您的需求作為我的指導。我的目標是產生一個代碼體,能立即幫助開發人員提高代碼質量,但也可以作為一項穩定而且可擴展的功能,開發人員可以將其加入代碼中滿足自己的需要。它必須能夠處理現實世界中足夠的復雜性,這樣才有用處,但又不可太復雜,以至于將 Codecheck 開發變成一種全職工作。    當我深入查看 ALL_ARGUMENTS 的內容時,我吃驚地發現那些參數列表會變得非常復雜。例如,在 Oracle9i 的環境中,一個參數可以將記錄的結合數組(以前稱為表的索引)作為其類型,其中記錄的一個字段是另一個結合數組,以此類推。非常坦率地說,我實際上不希望必須編寫代碼來處理這些參數全部的可能情況。    與此相反,Codecheck 將只基于“0級”參數來檢查和進行分析:這是指在 ALL_ARGUMENTS 視圖中的那些項目,當其出現在程序頭時,它們對應于參數列表。實際上,這可能是您為分析超載而所需的全部要素,但是全部的具體資料可能在進行某種其他的代碼檢查時派上用場。(在撰寫此文章時,我已確定了一種需要更多信息的情況:假如您將一個參數定義為表單 %ROWTYPE 的記錄,則 ALL_ARGUMENTS 和 DBMS_DESCRIBE 都不會提供其類型的信息。您可能必須比較那些行類型(1 級或更多級)的各個字段的數據類型以識別岐義。天哪。    定義測試策略    開發 Codecheck 的下一步是探究和定義測試策略。我曾提到過,我承諾編寫能夠滿足測試計劃的代碼,這種承諾影響著開發過程。例如,我在編寫如 Codecheck 等實用工具時的第一個沖動是,制作一個程序,接受一個程序包的名稱并在屏幕上顯示代碼檢查的結果。為了確定實用工具是否正確工作,我需要查看屏幕上的檢查結果并對其進行分析。這聽起來如何?熟悉嗎?可伸縮嗎?通常這種方法甚至對非常簡單的程序都無效。    Codecheck 測試計劃無疑會有很多測試方案,而其結果并不明確。換言之,除非我記住成功對所有這些測試方案意味著什么,否則我必須依靠手動的、直觀的驗證(先看這個窗口;然后將其與那個窗口的內容進行比較)。我需要用很長的時間完成一項測試(這是構成責任性的一項相當重要的要素),所以我很少進行測試 — 假如曾做過測試的話。這與我的保證相違反。    我需要找到一種更快捷方便的測試方法。使用 java 的許多開發人員轉向 Junit.PL/SQL 開發人員則利用 utPLSQL,一種用于 PL/SQL 開發人員的開放源單元測試框架。(申明:我是 utPLSQL 的創建者,盡管其他人現在也幫助進行實施并制作文檔。)
    我不會在本文中以很大的篇幅具體描述 utPLSQL 的起源、理論基礎或基本工作方式。假如您需要了解比本文內容更具體的情況,請訪問 http://utplsql.sourceforge.net/ 或 http://utplsql.oracledeveloper.nl.    utPLSQL 簡介    utPLSQL 是一種用于 PL/SQL 程序的測試框架(代碼以及使用這種代碼的進程的集合)。使用 utPLSQL,您可以構造包含單元測試過程的單元測試程序包,并依照 utPLSQL 的命名規范和測試機制來設計此程序包。然后您只須簡單地操作 utPLSQL 來測試程序或程序包。它運行所有測試并自動檢測該測試是否成功或失敗。它準確指出失敗的測試方案,使您更快地確定正確的測試方案并識別應用程序中錯誤的原因。    這種框架是基于極限編程的單元測試概念 ( www.XPRogramming.com) 以及 Junit(Java 單元測試框架)。下面是一些該方法進行單元測試的基本原則:    在編寫代碼前編寫單元測試。    少做編寫和更改,多做測試。    自動執行測試和生成報告:紅綠燈式的方法。    圖 1 表示 utPLSQL體系結構的一個簡化視圖,它是以強大有效的方式自動執行測試的一個往返旅程。下面對行程中的各站作一解釋:    調用 utPLSQL 測試過程執行測試程序包。utPLSQL 按照動態 PL/SQL 和命名規范來運行任何設置代碼,定位并執行單元測試程序,并進行必要的清除(“拆卸”步驟)。    單元測試過程調用“判定 API”,它將測試結果與“控制”條件進行比較。    判定程序將結果(通過或失敗)寫到下面的結果表中。    tPLSQL 測試讀出結果表中的內容,確定該測試的狀態。    utPLSQL 根據結果作出報告,或者通過 DBMS_OUTPUT 送到屏幕,或者通過 UTL_FILE 送到一個文件。    圖 1:utPLSQL 體系結構的往返旅程簡化視圖。PPT.PL/SQL構建代碼分析工具之從測試開始    讓我們來看一個很簡單的示例,從而大致了解單元測試程序包的內容。假設我已經創建了一個關于 SUBSTR 的封裝,答應在開始和結束點之間請求一個子串(一個簡單的函數)(列表 1)。    即使是簡單的或看似不重要的程序(如 betwnStr)也需要測試 — 而實際上我必須考慮大量的測試方案(包括 NULL 開始值、NULL 結束值以及開始大于結束等)。列表 2 顯示了測試程序包的一部分(全部測試包的內容請參見 ut_betwnstr.pkb)。關于要害部分的解釋,請參見表 1.    也許您會想,“多么單調乏味!我真的必須編寫所有那些代碼,只是為了測試這個簡單的函數嗎?”實際上,那些在測試領域工作的人都知道,測試一個應用程序所需要編寫的代碼數量經常比應用程序本身更多。對于這個特定的程序包和測試代碼的 utPLSQL 風格,您在某些情況下會生成全部的測試代碼。實際上,ut_betwnstr 程序包通過對 utGen.testpkg_from_string 過程的調用而生成,如列表 3 所示。    即使您不生成測試程序包,也經常可以找到其他方法,利用最少的代碼運行許多基于 utPLSQL 的測試 — 這正是我用 Codecheck 所做的工作。    將 utPLSQL 應用于 Codecheck    要利用 utPLSQL,我需要構建一個單元測試程序包并調用 utAssert 程序,以確定我的代碼是否通過其測試。但是,在進行這些操作之前,我需要精心制作我的測試方案。請記住:測試方案第一,其次才是代碼。    現在應該尋找靈感,暫停前進,考慮一下我所提供的實用工具。我希望它能夠驗證什么?那些能編譯但包含歧義超載的程序包的特例是什么?我能檢測到什么情況?有效超載的示例是什么?究竟我需要測試正面和負面的因素。經過一段時間以后,我給出以下的內容:    有效的超載    兩個超載程序帶有不同數量的非缺省參數。    兩個超載程序帶有相同數量的非缺省參數,并在數據類型方面具有足夠的差別(如 NUMBER 對 DATE)。    函數和過程具有相同名稱和參數列表,包括不帶參數的情況。區分這兩者并沒有問題,因為它們在代碼中的使用方法不同。    無效的超載    兩個超載程序具有不同數量的非缺省參數,導致歧義的參數列表。    兩個程序具有單個參數,數據類型相同但參數名不同。    兩個程序具有相同的名稱,具有單個參數,但卻是同系列中不同的數據類型。
    一個程序沒有參數,第二個程序具有一個帶缺省值的參數。    一個程序具有 N 個參數,第二個程序具有 N+1 個參數,全部帶有缺省值。    一個程序具有 N 個參數,其中 N-1 個參數有缺省值;第二個程序具有 N+1 個參數,其中最后兩個缺省。    一個程序具有一個參數,第二個程序具有兩個參數,其第二個參數有缺省值。    我肯定還將考慮其他測試方案,但這些已足夠繼續進行了。如何最好地進行上述方案的測試?我需要在程序包中定義這些不同的結合。讓我們稱之為 allargs_test.為每個測試方案使用一個不同的超載程序名稱,可能效果會較好。這樣可以保持事情清楚易辨而且非常有條理。實際上,我要創建一個表(參見表 2)。    此表有助于工作但還不夠。我還需要為這些測試方案分別指定期望的結果。它是有效的超載嗎?假如不是,它是如何失敗的?我如何用一種能使用 utPLSQL 自動運行測試的方式來獲取這種信息?問題太多了。    在本文中,我沒有指定所有測試方案的結果全集;我認為大致了解全部過程就足夠了。讓我們完整地運行表 2 中的一些方案,從而了解我需要測試哪些信息種類。考慮 samefamily1 過程。以下是這一超載的具體說明:    CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE samefamily1 (arg IN NUMBER);PROCEDURE samefamily1 (arg IN INTEGER);    很清楚,arg 參數的數據類型太相似了,它們都屬于數字型。因此,這將是導致故障的歧義超載。對 samefamily1 運行 Codecheck 的結果應該類似于:    allargs_test.samefamily:invalid overloading    結果看來是很基本的東西。我們只須說是或不是嗎?或者說無效或有效?在本例中,我想是這樣的。但我們再來看另一個更有趣的情況。考慮 noparms2 的開頭部分:    CREATE OR REPLACE PACKAGE allargs_test IS PROCEDURE noparms2 (arg1 IN VARCHAR2 := NULL,arg2 IN VARCHAR2 := NULL);    PROCEDURE noparms2 (arg1   IN   VARCHAR2 := NULL,arg2   IN   VARCHAR2 := NULL,arg3   IN   VARCHAR2 := NULL);    關于這兩個程序,Codecheck 會告訴我什么呢?讓我來計算可能引起 allargs_test.noparms2 無效或歧義的方式:    allargs_test.noparms2;allargs_test.noparms2 ('abc');allargs_test.noparms2 ('abc', 'def');    Codecheck 應該識別 noparms2 的總共三種不同的無效形式。這是由于所有的跟蹤缺省值答應我使用不同數量的參數來調用 noparms2.這比第一個測試方案復雜得多。當然,它可以變得更加復雜,這取決于超載程序的數量、參數的數量以及缺省值的有無。    我如何使用 utPLSQL 檢查上面所示結果的種類 — 自動檢查嗎?測試框架提供各種各樣的判定程序。例如,我可以檢查兩個標量值是否相等,這一點您在 betwnstr 中已經看到:    utassert.eq ('zero start', check_this, against_this);    但是,我還可以進行更有趣的判定。我可以檢查結果是否為 NULL.我可以檢查兩個表、兩個查詢、兩個文件、兩個數據庫管道或兩個集合是否相等。我可以檢查是否引發了特定的異常。利用最新版本 (2.0.10.2) 的 utPLSQL(感謝 Rainer Medert的貢獻),我甚至可以分析 DBMS_OUTPUT 的結果,看它是否符合我的預期。    有可能使用上述判定檢查來測試 Codecheck 嗎?我在較早前曾提及,我在編寫這種實用工具時的第一個想法是將結果顯示到屏幕。(實際上,Codecheck 的一個早期原型使用了這種技術,您可以在 args_analysis.pkg 腳本中找到此原型。)那樣我也許使用 utAssert.eqoutput 過程。    在對此考慮了一段時間后,我認為雖然從理論上講這個判定程序可能有效,但我確實不贊同圍繞 DBMS_OUTPUT 構建測試套件。為什么?假如我(或者其他使用并升級 Codecheck 的某個人)決定壓縮輸出的格式,將會怎樣?我將不得不更改單元測試程序包中的代碼。其底線是,通過 DBMS_OUTPUT 測試 Codecheck 的正確性使得數據(分析的結果)和表示(將結果顯示在屏幕上的方式)之間的界線變得模糊不清。因為這一方法總的來說不太好,所以我要尋找其他方法。    假如結果更加結構化,而不是在屏幕上顯示一行文本,則必將能夠更加輕易地驗證 Codecheck 正確性。讓我們重新查看 allargs_test.noparms2 的結果:    allargs_test.noparms2;allargs_test.noparms2 ('abc');allargs_test.noparms2 ('abc', 'def');    這里實際顯示的是以上任一調用中的內容,PL/SQL 不能識別我想要運行哪兩個 noparms2 過程。您可以在表 3 中看到另一種表示該信息的方法。我明白自己正在對比哪一對超載,并知道在每個超載中哪個序列的參數有歧義。我可以在數據庫表或集合中保存這些信息(既有我所期望的控制數據,也有來自運行 Codecheck 的測試數據)。然后,我就可以使用 utAssert.eqTable,檢查 Codecheck 對于控制表所分析的結果,該控制表由我建立并填入了我預期的結果。我已發現,通常填充和使用關系表要比集合輕易得多,因此在回顧迄今為止的思路后,讓我們繼續采用這一思路:
    我并不預備依靠 DBMS_OUTPUT 來驗證其正確性,但我確實希望將結果顯示到屏幕上,以便 Codecheck 的用戶可以方便地看到這些結果。究竟這就是該實用工具的全部要點。    我希望 Codecheck 利用那些相同的結果來填充數據庫表,這樣我就可以全面而精確地測試該實用工具了。    現在應該設計一個數據庫表(或者兩或三個),將可持續性數據結構的需求(和期望列表)考慮在內:    存儲控制和測試數據。不必將這些數據放在同一個表中,實際上我傾向于將其分開。這樣治理數據和執行測試將更加輕易。    跟蹤 utPLSQL 需要的所有信息,運行其測試并報告結果。    盡量減少在測試程序包中需要編寫的與 utPLSQL 集成的代碼數量。    我首先從最后一點開始講起。我在先前曾提及,測試代碼數量多于應用程序的情況并不少見。這很好,但我絕對不會介意獲得全面測試的同時不必編寫、生成或設計數千行代碼。有這種可能嗎?    實際上,這是我所希望的用于 Codecheck 的測試程序包的樣子(偽代碼形式):    BEGIN FOR every testcase LOOP Run Codecheck for the testcase scenario Compare test results to control table END LOOP;END;    換言之,我希望改變那種將所有測試方案的邏輯直接硬編碼到測試程序包中的方法(ut_betwnstr 是這種方法的一個示例),而代之以軟編碼方法,利用數據庫表中的信息作來驅動測試。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 无棣县| 张掖市| 湘潭市| 柘城县| 广元市| 津市市| 淮滨县| 天峻县| 德清县| 醴陵市| 临夏县| 齐齐哈尔市| 大方县| 扎囊县| 福泉市| 岳阳市| 连城县| 双城市| 邯郸县| 孟连| 孝昌县| 寻乌县| 罗江县| 新余市| 广安市| 凤阳县| 大方县| 宜宾县| 唐山市| 宁武县| 安仁县| 墨脱县| 河源市| 盐源县| 江口县| 宁国市| 抚宁县| 德安县| 牟定县| 海伦市| 隆安县|