O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

單元測試:Mocha、Chai 和 Sinon

11.337 visualizações

Publicada em

單元測試:Mocha、Chai 和 Sinon

Publicada em: Engenharia
  • Dating for everyone is here: ❤❤❤ http://bit.ly/2ZDZFYj ❤❤❤
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui
  • Follow the link, new dating source: ❤❤❤ http://bit.ly/2ZDZFYj ❤❤❤
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui

單元測試:Mocha、Chai 和 Sinon

  1. 1. 單元測試:Mocha、Chai 和 Sinon
  2. 2. Agenda ● Unit Test ● Mocha ● Chai ● Sinon ● 露天桌機結帳範例 ● QnA ● 練習 1, 2
  3. 3. 單元測試(Unit Test)
  4. 4. 什麼是 Unit Test? 以 function 為最小單位,驗證在特定情況下的 input 和 output 是否正確。 // 給定輸入為 1 和 2 var result = add(1, 2); // 預期得到輸出 3 if (result !== 3) { throw new Error('Failed'); }
  5. 5. 為什麼要做 Unit Test? ● 防止改 A 壞 B,避免不能跑的程式碼比能跑的還多 ● 明確指出問題所在、告知正確的行為是什麼,減少猜測時間 無折扣碼、無運費優惠、無自填金額下,計算 total_amount_discount_h 的值。預期 是 999,結果是 990。 1) test Service: InvoiceCheckoutParamsService Method: getDiscountedFinalPrice no coupon, no discount delivery, no custom price: AssertionError: expected 990 to equal 999 + expected - actual -990 +999 at Context.<anonymous> (/home/summer/samba/chongen22_20170904_PC_shopping_cart/www/include/resources/js/test/services/testInvoiceCheckoutPa ramsService.js:98:25)
  6. 6. 如何做 Unit Test? ● 使用 npm 等安裝 Mocha、Chai 和 Sinon 並 require ● 撰寫測試程式 ● 使用 mocha 啟動測試 ● 檢視測試報告,確認通過或未通過的項目 ● 根據測試結果進行調整:重構(通過)或除錯(未通過)
  7. 7. Mocha
  8. 8. Mocha ● Mocha 是一個 JavaScript 的測試框架,目的是管理測試程式碼。 ● BDD 提供 describe、it、before、after、beforeEach 與 afterEach 方法。
  9. 9. 語法 describe('hooks', function() { // 測試區塊 before(function() { /* 在所有測試開始前會執行的程式碼區塊 */ }); after(function() { /* 在所有測試結束後會執行的程式碼區塊 */ }); beforeEach(function() { /* 在每個 Test Case 開始前執行的程式碼區塊 */ }); afterEach(function() { /* 在每個 Test Case 結束後執行的程式碼區塊 */ }); // 撰寫個別 Test Case it('should ...', function() { /* 執行 Test Case */ }); });
  10. 10. 比較 TDD 與 BDD TDD BDD 全名 測試驅動開發 Test-Driven Development 行為驅動開發 Behavior Driven Development 定義 在開發前先撰寫測試程式,以確保程式 碼品質與符合驗收規格。 TDD 的進化版。 除了實作前先寫測試外,還要寫一份「可以執 行的規格」。 特性 ● 從測試去思考程式如何實作。 ● 強調小步前進、快速且持續回饋、 擁抱變化、重視溝通、滿足需求。 ● 從用戶的需求出發,強調系統行為。 ● 使用自然語言描述測試案例,以減少使 用者和工程師的溝通成本。 ● 測試後的輸出結果可以直接做為文件閱 讀。
  11. 11. Chai
  12. 12. Chai Chai 提供 BDD 語法測試用的斷言庫(Assertion Library)。 斷言庫是一種判斷工具,驗證執行結果是否符合預期。 -> 若實際結果和預測不同,就是測到 bug 了。
  13. 13. 範例 1:Assert assert(expression, message):測試這個項目的 expression 'foo' === 'bar' 是否為真, 若為假則顯示錯誤訊息 message。 var assert = chai.assert; describe('AssertTest', function() { var foo = 'Hello'; var bar = "World"; it('should be equal', function() { assert('foo' === 'bar', 'foo is not bar'); }); });
  14. 14. 範例 2:Expect / Should 預期某個值會相等。例如:預期 3 等於(===)2。 var expect = chai.expect; describe('ExpectTest', function() { it('should be equal', function() { expect(3).to.equal(2); }); });
  15. 15. Assert, Expect, Should 的差異 三者基本上都可完成相同工作,除了 ● Should 會修改 Object.prototype ● Should 在瀏覽器環境下,對 IE 有相容問題 ● Should 無法客製化錯誤訊息 assert.isTrue(foo, "foo should be true"); expect(foo, "foo should be true").to.be.true;
  16. 16. Sinon
  17. 17. Sinon 用來產生 Test Double(測試替身),簡單來說就是假資料,分為 3 種 ● Spy ● Stub ● Mock
  18. 18. Spy 對 function call 蒐集資訊,便於對測試結果做驗證。
  19. 19. Spy function compare(former, latter, callback) { callback(); return former === latter } describe('Spy', function() { it('測試呼叫次數', function() { var nameList = ['Nina', 'Ricky']; var callback = sinon.spy(); compare(nameList[0], nameList[0], callback); expect(callback.callCount).to.equal(999); // 該 function 被呼叫的次數 }); });
  20. 20. Stub ● 取代 function。與 Spy 不同的是,Spy 依然會執行真的 function,但 Stub 並不 會。 ● 適用以下狀況 ○ Ajax ○ Timer
  21. 21. Stub 範例 1 const uuid = require('node-uuid'); describe('測試 uuid 的長度是否為 36', () => { it('check length of uuid ', () => { var stub = sinon.stub(uuid, 'v4'); var mockId = stub.v4(); expect(mockId.length).to.equal(32); uuid.v4.restore(); }); });
  22. 22. Stub 範例 2:ajax function saveUser(user, callback) { $.ajax('/users', { first: user.firstname, last: user.lastname }, callback); }
  23. 23. Stub 範例 2:ajax describe('Stub: ajax', () => { it('should call callback after saving', () => { var ajax = sinon.stub($, 'ajax'); // 取代 ajax function,並不會真的呼叫 ajax.yields('Hello', 'World'); // 準備把傳入 callback 的參數 ['Hello', 'World'] 丟進去 var callback = sinon.spy(); saveUser({ firstname: 'Han', lastname: 'Solo' }, callback); ajax.restore(); // 清除 test double expect(callback.callCount).to.equal(777); // 該 function 被呼叫的次數 }); });
  24. 24. Mock 取代整個物件,包含完整實作細節。
  25. 25. Mock var opts = { call: function (msg) { console.log(msg); } };
  26. 26. Mock describe('Mock', () => { it('should pass Hello World to run call()', function() { var mock = sinon.mock(opts); mock.expects('call').once().withExactArgs('Hello World'); opts.call('Hello World'); mock.restore(); mock.verify(); }); });
  27. 27. Chai Assertion vs Sinon Assertion 推薦使用 Sinon 的 Assertion,因為 ● 不需刻意客製化報錯,即可反應問題所在 assert('foo' === 'bar'); // AssertionError: Unspecified AssertionError assert('foo' === 'bar', 'foo is not bar'); // AssertionError: foo is not bar var expected = {x: 999}, actual = {x: 1, y: 2}; sinon.assert.match(actual, expected); /* AssertError: expected value to match expected = { x: 999 } actual = { x: 1, y: 2 } */
  28. 28. 露天桌機結帳範例 InvoiceCheckoutParamsService.js ● 取得 discount id ● 取得 coupon id ● 各類情況下,是否正確計算 total_amount_discount_h 的值 ● 各類情況下,是否正確計算 total_amount_h 的值
  29. 29. QnA ● Q:寫測試是否會增加額外工時? A:工時是一定會增加的,個人經驗是增加一倍。 ● Q:除了程式碼的品質保證外,還有什麼好處? A:記錄規格。測試案例如同告知開發者規格的細節和範例,再也不怕同事離職, 無人可問。
  30. 30. 練習 1 function isGod() { return true } describe('猜猜看會不會出錯', function() { it('expect 練習', function() { const OK = 999; expect(isGod()).to.equal(OK); }); });
  31. 31. 練習 2 describe('猜猜看會不會出錯', function() { it('練習 2', function() { assert(null == undefined, 'null 不等於 undefined'); }); }) // 獎品是一根大香蕉

×