# 軟體工程 Week 4 ###### tags: `軟體工程` # 測試 ## ACM 調查 * 校園很少介意 ## QA & QC ### Good quality product requirement (將軟體視為一項產品) * Quality control 品質控制 * Quality assurance 品質確保 * Testing 軟體測試(品質確保中的一環) * 把Bug抓出來的一手段 ### 製造業案例 * 希望生產與可販售的數量相符 * Process Improment(工業工程領域):製造流程改,提高良率 * 最好提升品質方式,使用機器 * 但機器有磨損問題 * 生產線: * 讓每個人做簡單工作,使他們【不易出錯】 * 不需要太過聰明 * 切割小步驟,每個步驟能在最短時間完成 * 使其發現產品問題不困難 ### 能如法炮製嗎? * 並不能 * 軟體發展是設計的工作 ### Programmer VS Assembly line worker (生產線作業員) * Programmer * requires perfection ### The Big GAP ![](https://i.imgur.com/M3sbvO0.png) * Demo-Oriented reasearch * Don't Touch * research prototypes * Major Features are usable (主要功能) * prove of concpts (概念證明) * not responsible for bugs (不負責任) * user friendly not guaranteed (不保證) * crappy UI (糟糕的UI) * Product * all features * bugs are not allowed * usable * user friendly * the generic data format * performance is tuned. * UI is well designed and pleasant ### Other engineer VS software engineer * Other engineer * Idea * Marketing(Requirement) Analysis * Analysis and Design (分析與設計) * Manufacturing (QC) (製造) * Testing (QA)(測試) * Release product (產品出廠) * software engineer * Idea (概念) * Requirement analysis and specification (100% design) (需求分析與規格) * Design and analysis (分析與設計)(100% design, QC here?) * Implementation (程式實做) (95% design?, QC here?) * Manufacturing (製造)(compilation – no cost manufacturing) * Testing(測試) ## Tradiction 1. Marketing 2. Develop 3. QAs(Testing) * QAs 必須與Programmer 站在對立面 * 管帳的不管錢,管錢的不管帳 * 法官判案,承認判案是錯的 ## Software Testing V model ![](https://i.imgur.com/mrM7XxK.png) * 瀑布模型 開發模式 ### Testing 1. 模組設計(小塊) => Unit Test * Programmer 3. 設計與分析 => Integration Test * Programmer / QA 負責 4. 規格 => System Testing * 系統已經完成 5. 需求 => User Acceptance testing (UAT): 驗收測試 6. Regression testing(回歸測試) 7. Alpha testing: 整合測試完成後,程式功能皆已大致完畢且完成測試(程式一Run就當掉都修的差不多嘞) * Most software function & feature are basiclly completed: 程式碼已經完成 * freezing : 新功能不再添加功能。All function are tested, no function will be added beyond this point * Serious flaws(high severity) are sloved and addressed(show stopper) 8. Beta Testing * Sub-serious bug all fixed: 嚴重Bug 皆以解決 * Text plan has been completely excuted: QAs 已經完成 Testing Report * Bug discovering rate is lower than fixing rate,發現頻率低於修復頻率 ## SDLC(Software Development Life Cycle) ![](https://i.imgur.com/LjNO8lF.png) * Release * Bug discovering rate is lower than fixing rate for 【long period of time】 * The version after fixing bugs has been regressively tested (regression test): 版本修復後,且經過回歸測試 * Quality is formally proved by QA team: QAs正式證明質量 * All documents are ready: 文件皆已經齊全 ## Testing tasks to be done * Write Test plan * often seen in large software company with formal QA team * write test cases, prepare test data * test case management * file bugs * Bug 回報系統(文件) * regression testing * test automation (with tools): 測試自動化 * QA team 來做 * stress testing/load testing * security testing * test as assets. ### How to plan * (要或不)測什麼 * 測試代價有多高 * 前後順序 ### 很重要的一句話 #### No test case No quality # Test Case * Test ID * Revision History * Summary * Tested Story * Creator * Test Step * ![](https://i.imgur.com/A3O8VeC.png) ## Test ID * 可包含之元素 * Test Suite name * Computer or Requirement abbreviation(縮寫) * ID 值可使用有意義之值 * A: automatically Excuted : 測試自動化 * M: Manually Excuted : 需透過人工 * P: Positive case * N: Negative case : 故意操作超出範圍之值 * B: Boundary case : 故意測試邊界值,如:<0,會測試0與1 * 0: cast priority * 1....9 ## Bug Report System * 紀錄Bug * 確認測試足夠的 * 能夠與未來的人溝通 * 若有人來詢問Bug代表敘述不清楚 * Attach any files * input file * output file * dump * 也可利用 OBS: 影片錄影 ### Severity of Software Defect * Severity 1(Show Stop): 非常嚴重,一跑就當掉嘞 * Severity 2: 不會當掉,但會無法繼續操作 * Microsoft 1-30 # Devops ## Regression Testing * ![](https://i.imgur.com/R4PeWei.png) => ![](https://i.imgur.com/N9RqFY1.png) * 敏捷開發 => 回歸測試自動化 ## Buttom up But Fow ### AFILE * 不斷 Release * 先顯示可以動的部分,不等成品完成 * Quality 要由底部向上完成 ### Module Test * 雖然不是整段程式,屬於片段程式,但還是能夠進行測試 #### Test Bench * Module under test * Component under test * Program under test * dependecy * 需要透過其他的人合作的程式組件才能執行 * 需建置一個API Server才能夠處理 * Test Driver * ![](https://i.imgur.com/x45lksp.png) * Test Runner * Dummy r(): 假的 = fack * 使用造假輸入,並回傳 * 設定中斷點 * 使用假的 Server ### Testing in isolation ![](https://i.imgur.com/gT1WWAg.png) ## Parafigm Shift * 徒然讓Proggramer 加入 Testing文化 * Tools: Coverage ### Google * 讓Proggramer 工作增加但薪水也增加 * 讓Proggramer 每天習慣與實踐 ### Unit Test Benefits * Unit Test = Black Box + While Box * 有Source Code * Unit Test 1 : Unit testing provides documentation (測試及文件) * basic picture * carry information * appropriate * inappropriate * Unit Test 2 : Reusable and Reliable (可重用性且可靠性) * 因為由Buttom up , 因此程式品質本就好 * Unit Test 3 : Unit testing help gauge performance (能幫助測量程式):(你可以在更早的時間進行效能測試) * Unit Test 4 : Unit testing improves code coverage (改進測試覆蓋率) ## Bottom up Vs Top Down * Project vs Product * Short-term fix product vs long-term maintained project? * 你的老舊系統 (legacy) 要不要回去補單元測試? (其實你想補也大概補不動) * 一個可能的 good timing – 老系統因為效能,功能改善得重構 -> 圈出一個範圍補單元測試 # Junit * @Test * assertEquals(比對值,呼叫函數<被Test>) * ![](https://i.imgur.com/W7NSCNE.png) * BeforeEach : Test Case Run之前會先呼叫 * 不能添加 Static * AfterEach: Test Case 每個Run完成以後呼叫 * 不能添加 Static * AfterAll : Test Case 全部 Run完成以後呼叫 * 一定要添加Static # Test Oracles * 能判斷 Program Behavior 是否出錯,針對程式的輸入輸出做一比較 * monkey tests: 隨便亂點按鈕 * Teating automation 測試自動化困難之處 * 無法判別程式的正確與否 * 決定規格與一致性是否不符合 * 規格=> 正確性 * * 人是最厲害的 Test Oracles * 聖杯(holy grail)問題 ## About * 驗證是否與程式執行結果一樣 * 視為一個黑箱 * 使用CUT 建立物件 ### Unit Test單元測試 * Unit Test = Black Box + White Box * 有Source Code * 需要額外增加 * 讀取Internal Value(內部變數)判斷 * Construction injection * 當你需要使用 fake object * 像是 test stub, mocks. * 案例一: Construction injection #### white box * 能夠知道source code * 推倒Test Case * 能夠知道 Iternal behaviors 的狀況 ### 案例一: Construction injection * ![](https://i.imgur.com/kRxZevz.png) * 在Test Case呼叫後, * 可提供給其他函數使用: Object 都會重新被建立,重新New ### 案例二: assertTrue Run For(){} * ![](https://i.imgur.com/NGEtZPs.png) * ![](https://i.imgur.com/Krf3dcY.png) ## True Oracle ![](https://i.imgur.com/Fr0ojtF.png) * X 你寫的Program: 不確定是否正確 * 應用情境: 舊版改寫須重購、改良 * 不一定存在 ![](https://i.imgur.com/VZ7qh0F.png) ## Partial Oracle ![](https://i.imgur.com/rFtE9iI.png) * X 你寫的Program: 不確定是否正確 * Detect X 輸出的值是否正確,不正確輸出 Failed * 並不容易撰寫 * AVL Tree 案例實作 * 應用情境: * Program Prove * Precondiction PostCondiction ![](https://i.imgur.com/5Icubrw.png) ## Test-Oriented oracle(xUnit test) ## ParameterizedTest vs Partial Test Oracles 哪裡不一樣?? # 要寫多少測試才夠 * Code Coverage * Paryition Test * Boundery Test * Negative Test ## Code Coverage ![](https://i.imgur.co:m/f7od7i9.png) * Statement coverage: 每條路都走過 * ![](https://i.imgur.com/uXGf0pE.png) * You only need 3 test cases to have each statement at least executed once. * Testing 的最低測試標準 ## Branch coverage: 分支測試 ![](https://i.imgur.com/KB9PFmB.png) * there are 3 branches, so at most 2 * 2 * 2 branching * ![](https://i.imgur.com/bcHaA9L.png) ## Path Coverage: 窮舉測試 ![](https://i.imgur.com/yOnmbEa.png) * ![](https://i.imgur.com/XBHOoOg.png) * 最困難達成,理論上達不到 * exhaustive testing * ![](https://i.imgur.com/vB0r6eP.png) * Omega(大寫Ω,小寫ω): infinite 無窮 ## Summary 總結 ![](https://i.imgur.com/DTF9STi.png) * 左座標: 現實中是否能夠達成 * intractable: 棘手的;太困難的 * feasible: 可行的 * 金管會 要求到 Branch * 基本上不可能達到 * 根據時間與資源決定測試的位置 ## Partition Test * 人類最古老的測試理論 * ![](https://i.imgur.com/ViwHjyo.png) * Input 以及對應的 Domain * 只需要挑橢圓形區域中的一個就可以嘞 * Equivalence partitioning(partition testing) * White box 白箱測試 * 案例一: Bobble sort * 測試案例 * ![](https://i.imgur.com/SFrBhyu.png) ## Boundery Test: 測試邊緣人,不只是邊界 * 通常 Boundery Test + Partial Test * boundery values 被暴露出來 * ![](https://i.imgur.com/n2g5ymX.png) * X=Y * X=0,整數最大值、最小值 * Y=0 * ![](https://i.imgur.com/TmlSHqh.png) * ![](https://i.imgur.com/SXLt6yT.png) * ![](https://i.imgur.com/j1ZzXAd.png) * ![](https://i.imgur.com/TG768yB.png) * 999999..., 根據規格書 * 字串超出範圍 ## Negative Tests :(給不合法,超出範圍的參數值,看看你的程式碼會不會掛掉) * 測試字串超出長度 * 字串不符合規定的跳脫字元 * 有非Ascii亂碼 # Unit test in Isolation ![](https://i.imgur.com/NhvuNYU.png) * Other Class 讀取檔案 * 不會包那麼大包的原因 * 因為會讓測試成本、代價過高 * 如改寫資料庫 * 因此使用假的Dummy Object來做取代 ![](https://i.imgur.com/eXv56xh.png) ## Mocks and Other Test Double ![](https://i.imgur.com/ylLDS5L.png) * Dummy Object * New 一個 Dummy 物件,只為了能夠讓Player建立出來 * Fack Object * 已經有Interface,需要去繼承 * 建立一個新的Class * Test Stub * Constructor injection * 讀檔案,會直接讀取,但測試實不希望干擾到系統 * 建立Constructor injection: ![](https://i.imgur.com/GGzyADT.png) * 將CUT的Code做更動,放入假資料mgr Fack Object VS Test Stub?? # External Dependency: Test Stub ## External Dependenncy in a CUT * 一個物件與你的系統必須有互動 * 對他沒有控制力 * 初始代價過高 * 牽涉到不可分離性: 會做實體的操作 * 對資料庫修改 ## A Stub * 可控制的取代依存之物件,創建一個假的模擬你需要的物件 * A stub can never fail the Test * Intercept 攔截 * Unit Test單元測試的基本 ### Aproach 1 : Fakes via Duplication: 類似Copy ![](https://i.imgur.com/4TMF58e.png) ![](https://i.imgur.com/lzb0zGM.png) * 無法隨心所欲單元測試 ## Aproach 2 : Dependency Injection : 修改建構值 * constrictor Injection (建構值隔離) * 只需要動態轉換物件即可 * Constroctor 只需要專注初始化記憶體與變數即可 ### 物件導向的原則: LoD(Law of Demeter) * 是否有複雜化的行為 * 給店員25元,是直接給錢包,還是拿25就好D * 建構值: ![](https://i.imgur.com/8uwD2LZ.png) * engine = factory.... => 不應該出現在這裡,汽車何必知道工廠的資訊 * 應該在外面New 再丟進來 * 太多的物件繼承 : ![](https://i.imgur.com/n8UtxlU.png) * 有太多的問號,不知道該測哪一個 * 物件繼承被濫用 * ![](https://i.imgur.com/G3yEvHh.png) * 正確 : ![](https://i.imgur.com/j22719o.png) * If you dont't take advatage of polumorphism : 如果沒有要用多形,請把繼承拿掉 * B繼承A,B is A * 把不對的繼承換成Composition * (絕對不要!!)不要用繼承來Reuse你的Code * Testability * Seams (介面) ### Exaple 3 ![](https://i.imgur.com/iaqn2Cr.png) * 該測試為甚麼難寫 * 牽涉兩個物件 * Customer * Money( wallet ) * 歸咎於你的Poor物件導向 * ![](https://i.imgur.com/dZM5yxJ.png) * 修正後的結果: ![](https://i.imgur.com/tZTBInz.png) * 將原本在purhase 呼叫 錢包 的動作,更改成只Input錢錢 * 相較上述,明顯少了兩個物件的宣告 * 原本應該專注於 Good,卻有多放入Money與Customer,以至於無法 test isolation * 若兩個物件是正確的倒還好 * 最壞情況,會導致無法準確精準測試Good ## Approach 3: Testing with Mocking Framework * legency 老舊系統是否能夠Testing?? * 想補也很難補救 * 可能需要重構 * 透過圈出小範圍 ### Proble, with Stub * 必須重新撰寫或新增另一個 * 測試不一樣的測試資料 * 動態測試資料 * 當測試Stub 會隨著修改或新增 * Stub 會隨著不一樣的條件回傳不同值 * 當 Interface 更新 也需要一起更新 * #### Fragility of test case: 脆弱 * 開發時的變動,也讓你經常更動一大堆單元測試,表示程式或單元測試有一些脆弱與易碎性 * 開發階段常更動 * Class * methods * methods signature * interface * 必須探討開發流程是否有問題 * 物件導向 * 系統設計 * 隕石開發法 * 上帝 * 老闆 * 客戶端 ### Mocking framework * JUnit * Mockito * JMockit * EasyMock #### Mocking to replace * 相關方法: ![](https://i.imgur.com/Bivfe5R.png) * 程式碼案例:![](https://i.imgur.com/B65JecL.png)..... ![](https://i.imgur.com/7nKBcci.png)..... ![](https://i.imgur.com/KlDZYMm.png) * tuormock => TeachStub取代: ![](https://i.imgur.com/9wL1TCW.png) * 語法: ![](https://i.imgur.com/cC70fEp.png) * 介面宣告: ![](https://i.imgur.com/kxuKbIY.png) * tutormock.checkin(): 確認是否有值 * When(...).thenRewturn(...): 負責造假 * V.S.: ![](https://i.imgur.com/Vski0Ek.png) * 都被取代掉了 * 語法2(callBack): ![](https://i.imgur.com/IPifg5B.png) ### Another External Dependecy: Mock ![](https://i.imgur.com/MrliHFp.png) * 測試的麻煩事情 * TCP 測試 * 需要再準備一個TCP Server * 無準備,會卡住 Block * ![](https://i.imgur.com/SttI0q4.png) * #### State-Based vs Interaction testing (behavior testing) * 如何知道灑水裝置定時灌溉 * state-based: 在乎結果,有許多狀況未被測試到,較為不精準(shit屎) * 跑12小時 * 跑完後 * 檢查花草 * 檢測土壤濕度 * 是否枯萎 * 目前大部分的測試 * Interaction Testing: 在乎過程 (behavior object) * 頭尾安裝: 流量偵測器 * Mock: 0記錄所有呼叫行為 #### TestStub vs Mock * State-base Testing * A stub can never fail the test * Stub 通常模擬 內部物件之正確行為 * TestOracle 所要 assert 的正確性在 CUT的行為,不會再Stub 裡面 * ![](https://i.imgur.com/8aUfv7M.png) * assert(,XXX()) * Interaction-Based * Mock 通常模擬 內部物件接收 SUT 送出的Information * Mock 會記錄CUT與自己的所有內部互動 * Tesr Oracle 所要的 asser 的正確型,會在Mock 收的訊息 * ![](https://i.imgur.com/zntAGkY.png) * 比較Care * 呼叫什麼 * 每一次的參數 * API 倍呼叫的頻率 * 常見行為 * Real external objects (dependency) 在呼叫之後沒有回傳值,或是任何可以讓你驗證external objects 狀態(state)的方法 * 硬碟讀寫 * 資料庫讀寫 * 網路讀寫 (這是最常見的例子) * 檔案讀寫 * Real external object 會實質更改資料 * Real external object 有 nondeterministic (不確定性)行為 * Real external object 很難觸發 * Real external object 很慢 * Real external object 是 user interface * Real external object 使用 call back * Real external object 的行為不容易觸發 * verify().XXX(): 根據流程驗證,是否是相同 Func ![](https://i.imgur.com/DXnAk1b.png) * ![](https://i.imgur.com/wkBxEEG.png) ##### Exception Handling ![](https://i.imgur.com/tfC2Wi5.png) ![](https://i.imgur.com/2jPuNSb.png) # test-isolation ![](https://i.imgur.com/O0RB2of.png) ![](https://i.imgur.com/NYj2EwE.png) ![](https://i.imgur.com/jcvQQPY.png) * DummyObject * ![](https://i.imgur.com/If0TOnz.png) * Fack Objet * a Test Stub acts as a control point to inject indirect inputs into the SUT the Fake Object does not. It merely provides a way for the interactions to occur in a self-consistent manner ## Exceptions from teststub ### 真實的 external dependency – Teacher 會丟 exception 嗎? * SC SHOULD catch 並且處理掉 * SC IS DESIGNED NOT to catch,pass the exception upward * * 如果會,那 tutormock 也應該模擬丟出 exception * 一般而言 test stub never fail the test,而且模擬所有正確的行為 * 產生了一個不存在學生的名字 * 呼叫 Teacher 的時候,傳的參數都沒有問題,但是真實 Teacher 因為學校的資料庫系統有問題 #### Case 1 :StudentCollection (SC) SHOULD catch (by design) ![](https://i.imgur.com/tQkoxpB.png) 一般的原則是你在 test code 裡面是不會去 try catch 的。其原因如上 #### Case2: SC IS DESIGNED NOT to catch,pass the exception upward ![](https://i.imgur.com/hC4H7M9.png) test cases ALWAYS fail,你的 DEVOP pipeline 永遠都不會過 !