# 三之 1、 JS 102 測試方法 ###### tags: `JS102` `JavaScript續` `2020七月第五週` `進度筆記` `Lidemy心得` `7/29 --- ## 怎麼測試寫的程式 , function 寫得對不對 ? 通常一開始蠻常用 `console.log` , 或是用邊界條件 (edge case) 去測試,但這樣會有很多的 `console.log` , 不是很容易跑。 因此可能在 `console.log` 內加上 `===` 做測試資料。 因此不好規模化,很難大量執行。 --- # 三之 1、 JS 102 Jest 使用前輩們的框架 ###### tags: `JS102` `JavaScript續` `2020七月第五週` `進度筆記` `Lidemy心得` `7/29 --- Jest 可以幫助測試的 framework , 可以跟著使用: [jestjs.io](https://jestjs.io/docs/en/getting-started.html) [Jest | 讓 Jest 為你的 Code 做測試-基礎用法教學](https://medium.com/enjoy-life-enjoy-coding/%E8%AE%93-jest-%E7%82%BA%E4%BD%A0%E7%9A%84-code-%E5%81%9A%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6-%E5%9F%BA%E7%A4%8E%E7%94%A8%E6%B3%95%E6%95%99%E5%AD%B8-d898f11d9a23) ## jest 啟用方式 yarn : `yarn add --dev jest` 使用 yarn 的話因為預設安裝比較多 library , 所以測試結果比較有花俏的顏色、漂亮的結果。 npm : `npm install --save-dev jest` npm 執行的話則要多安裝另外的 library , 不然顏色比較單一難以辨別。 如果用 yarn 指令, 會發現他載了蠻多 library : ![](https://i.imgur.com/LZzkY0N.png) --- ## 測試與 code 通常測試歸測試,本身的 function 是本身的,是分開進行,所以會把 function exports 出去,如 `module.exports = 函式名` 。 所以我們先建立一個函式(其實已是模組): ``` function repeat(str, times) { var result = '' for(var i=0; i<times; i++) { result += str } return result } module.exports = repeat ``` 檔名是 index.js 。 --- 再建立一個測試用的檔案: `touch index.test.js` 檔名是 index.test.js 。 接著開啟,輸入: ``` var repeat = require('./index') console.log(repeat('a', 5)) ``` 去引用 index.js , 成功後會看到: ![](https://i.imgur.com/8NGnL70.png) --- ## 套用 jest 把這段套到 index.test.js 檔案內,置換掉 `console.log(repeat('a', 5))` : ``` test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); ``` ES6 語法`() => {}` 其實等於函式 `function() {}` 。 --- 而我們希望印出 5 倍的 a 祝福量,因此: ``` var repeat = require('./index') test('a 應該重複 5 次應該要等於 aaaaa', function() { expect(repeat('a', 5).toBe('aaaaa'); }); ``` jest 提供一個 test 的 function , 像是(輸入中文也可) test('a 應該重複 5 次應該要等於 aaaaa', function() { expect(repeat('a', 5).toBe('aaaaa'); }); expect (裡面接函式的結果),讓 a 重複 5 次,結果 (.toBe) 'aaaaa' , 可以這樣看,__這個 reapeat 的結果,我們 expect 它應該要是 toBe 多少__。 或是也可以這樣寫: ``` var repeat = require('./index') function test1() { expect(repeat('a', 5).toBe('aaaaa'); } test('a 應該重複 5 次應該要等於 aaaaa', test1); ``` --- ## 在 script 中設定指令 寫好後在 CLI 下用 node 指令跑會出錯,因此必須去更新 package.json (如果是跟 npm 裝在同一個 node_modules 資料夾下) 的 scripts 修改: ![](https://i.imgur.com/RDyAZWe.png) 在 devDependencies 下將 `echo \"Error: no test specified\" && exit 1` 換成 `jest index.test.js` 。 並將 `"scripts": { "test": "jest --coverage" }`,為其加上 --coverage 參數,可看測試報告。 --- ## 測試檔案該放哪 ? test 檔案先放入 __test__ 資料夾內 , 而 js 檔案可放入 JS 資料夾。 jest 預設是 , 先找 __test__ 資料夾內的檔案來做測試。 如果有啟用資料夾管理,在 test 中引入的 js 檔案,則需注意檔案路徑。 之後就使用 jest 來跑 (不是 node 指令),因為 jest 不是 global 的安裝在電腦內,它是局部的裝在某個資料夾。 jest 全域指令: `npm install jest -g // -g 代表全域;` --- ## 還沒好,安裝 babel 並設置檔案 config 使用指令安裝 babel `yarn add --dev babel-jest @babel/core @babel/preset-env` 。 接著可以用指令 `JEST init` , 修改配 jest 配置,如果 jest 不是全域安裝,則需使用 `yarn JEST --init` 。 參考文章: [JEST 單元測試學習筆記 | Getting Started、Using Matchers](https://medium.com/unalai/jest-%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-getting-started-using-matchers-6f99ca314ca8) [使用 Jest 進行 Unit Test](https://medium.com/@pvt5r486/%E4%BD%BF%E7%94%A8-jest-%E9%80%B2%E8%A1%8C-unit-test-ab53472990fc) [Jest | 讓 Jest 為你的 Code 做測試-基礎用法教學](https://medium.com/enjoy-life-enjoy-coding/%E8%AE%93-jest-%E7%82%BA%E4%BD%A0%E7%9A%84-code-%E5%81%9A%E5%96%AE%E5%85%83%E6%B8%AC%E8%A9%A6-%E5%9F%BA%E7%A4%8E%E7%94%A8%E6%B3%95%E6%95%99%E5%AD%B8-d898f11d9a23) --- ## 照著跑出了點問題 但我照著, [jest.io](https://jestjs.io/docs/en/getting-started.html) 的 getting start 下去跑,一開始 sum.js 和 sum.test.js 的檔案放同層(同資料夾內),使用指令 `yarn test` 也可用 `npm run test` 或是 `yarn run test` (因為之前有在 scripts 下更改過 test 的指令) , 但顯示 fail 。 把 sum.test.js 更改 , require 的路徑,指定路徑也都沒效: ``` const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); ``` ![](https://i.imgur.com/ZNGIWAq.png) 用指令 `npm run test` 或是 `yarn run test` 均失敗... --- 後來直到這篇文章 [Node.js中的require是如何工作的?](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/662167/) 解決了我的問題; 原來 require 照著同層的位置跑,之後會再找上一層(其實課程內也有說到,不過不過我沒想到會有點後來去查才知道運作方式) , 好 , 所以我就更改了: ``` const sum = require('../sum'); // 就是這個 . 卡了我一陣 囧; test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); }); ``` ![](https://i.imgur.com/uCLQBNr.png) 我把 sum.js 放在 _test_ 資料夾的上面一層資料夾(之前讀不到) ,然後重新指定他讀上一層,總算才成功。 --- ## 也可以針對單一檔名跑: 可以將 package.json 複製到測試資料夾,然後在 package.json 檔案內找到 scripts 後,修改: ``` "scripts": { "test": "jest index.test.js --coverage", // 可以指定 單一檔名,例如這次我指定了 index.test.js ; "test1": "node index.js", "test2": "node index2.js", "serial": "node index.js && node index2.js" ``` --- 而測試資料夾內跟 packags.json 檔案同一層的是, index.test.js 測試用檔案,內容為套用 jest 的形式: ``` var repeat = require('../index') // 前面加了 ../ 會指定上一層的 index.js 檔案; test('a 應該重複 5 次應該要等於 aaaaa', function() { expect(repeat('a', 5)).toBe('aaaaa'); }); ``` 而課程中測試的 index.js 模組檔案內的函式放在上一層資料夾: ``` function repeat(str, times) { var result = '' for(var i=0; i<times; i++) { result += str } return result } module.exports = repeat ``` --- 再用 `yarn run test` 指令可以看到: ![](https://i.imgur.com/nqMGMde.png) --- 全域指令: `npx jest` 也可以指定檔案,例如: `npx jest index.test.js` , 比較新的 npm 版本會附上這個 npx , 這會從系統下去找: ![](https://i.imgur.com/Swfrn1j.png) 中文敘述顯示亂碼的話要套用其他套件。 --- ## 可以多來幾個 test ~ 如果在想要用多一點方式來測試函數 (模組) 的功能,可以在測試檔案內這樣做,例如: ``` var repeat = require('../index') // 前面加了 ../ 會指定上一層的 index.js 檔案; test('a 應該重複 5 次應該要等於 aaaaa', function() { expect(repeat('a', 5)).toBe('aaaaa'); }); test('abc 應該重複 1 次應該要等於 aaaaa', function() { expect(repeat('abc', 1)).toBe('abc'); }); test('"" 應該重複 10 次應該要等於 ""', function() { expect(repeat('', 1)).toBe(''); }); ``` ![](https://i.imgur.com/A1NtPNq.png) 一個 test 就是一行,多行 test 代表可以同時測試好幾個方法。 會比用 `console.log` 手動慢慢測試,更方便一點。 --- ## 多行測試可以再集中一點的組合-單元測試 單元測試 (Unit test) 是可以將測試函數 (模組) 的功能,在測試檔案內這樣做集中組合,例如: ``` var repeat = require('../index') // 前面加了 ../ 會指定上一層的 index.js 檔案; describe('測試 repeat', function(){ test('a 應該重複 5 次應該要等於 aaaaa', function() { expect(repeat('a', 5)).toBe('aaaaa'); }); test('abc 應該重複 1 次應該要等於 aaaaa', function() { expect(repeat('abc', 1)).toBe('abc'); }); test(''"" 應該重複 10 次應該要等於 ""', function() { expect(repeat('', 1)).toBe(''); }); }) ``` 這樣寫比較有結構,像是把這些測試都歸在跑測試 repeat 的群組下。 ![](https://i.imgur.com/xTKzcis.png) --- # 三之 2、 JS 102 先測試再開發 ###### tags: `JS102` `JavaScript續` `2020七月第五週` `進度筆記` `Lidemy心得` `7/29 測試驅動開發 (Test-Driven Development ) 。 接到一個需求 -> 寫好 function -> 測試,但 TDD 的精神是倒過來,亦先從測試開始。 範例: 1. 先從測試開始,且盡量寫得詳細點,盡量 try 邊角案例之類,但沒有寫任何 function 或是 code , 所以會看到 jest 測試是 fail 的情況。 2. 這樣就會知道要改哪,然後開始寫個大概的 function 或是 code , 寫完後開始抓錯,找 bug 。 3. 逐步修正,更新版本,檢查程式碼,每改一次 code 就執行測試直到對為止。 好處是希望去掉多餘的 code , 來提高質量,避免過度設計的浪費成本; 缺點是有可能會忽略實際使用需求,開發速度變慢、維護工作量增加等等。 Z>B 或是 B>Z 的正反觀點爭議蠻多~ --- 參考文章: [Test-Driven Development 解決了什麼問題?或是製造更多問題?](https://medium.com/fcamels-notes/test-driven-development-%E8%A7%A3%E6%B1%BA%E4%BA%86%E4%BB%80%E9%BA%BC%E5%95%8F%E9%A1%8C-%E6%88%96%E6%98%AF%E8%A3%BD%E9%80%A0%E6%9B%B4%E5%A4%9A%E5%95%8F%E9%A1%8C-937db879f695) [TDD 開發五步驟](https://tw.alphacamp.co/blog/tdd-test-driven-development-example) ---