jest java_?使用jest進行測試驅動開發

前言

本文將使用jest進行測試驅動開發的示例,源碼在github。重點說明在開發中引入單元測試后開發過程,以及測試先行的開發思路。

本文的重點是過程以及思維方法,框架以及用法不是重點。

本文使用的編程語言是javascript,思路對其他語言也是適用的。

本文主要以函數作為測試對象。

環境搭建

假設項目結構為

.

├── README.md

├── package.json

├── src

├── test

└── yarn.lock安裝依賴

yarn add --dev jest打開package.json, 修改scripts字段

"scripts": {

"test": "jest"

}

之后把測試文件放在test文件夾下,使用yarn test 即可查看測試結果

開發

現在要開發一個函數,根據傳入的文件名判斷是否為shell文件。

先做好約定:shell文件應該以 .sh 結尾

shell文件不以 . 開頭

函數為名 isShellFile

下面來看下開發步驟是怎么樣的。

文件初始化

在src目錄下新建 isShellFile.js

touch isShellFile.js

然后一行代碼也不寫,在test目錄下新建 isShellFile.test.js

可以注意到,測試文件的名與源文件名類似,只是中間多了個 .test

touch isShellFile.test.js

第一個用例

打開測試文件 test/isShellFile.test.js ,編寫第一個用例,也是最普通的一個: bash.sh

const isShellFile = require('../src/isShellFile')

test('isShellFile', () => {

// 調用函數,期望它返回值為 true expect(isShellFile('bash.sh')).toBeTruthy()

})

運行 yarn test , 結果如下:

FAIL test/isShellFile.test.js

? isShellFile (2ms)

● isShellFile

TypeError: isShellFile is not a function

^^^

3 | test('isShellFile', () => {

4 |

> 5 | expect(isShellFile('bash.sh')).toBeTruthy()

| ^

6 | })

失敗是意料之中的,因為 src/isShellFile.js 一行代碼也沒寫,所以測試代碼中第5行 isShellFile 無法進行函數調用。

完善源文件src/isShellFile.js

module.exports = function(filename) {

}

這樣 isShellFile 就可以作為函數被調用了。

再運行 yarn test

FAIL test/isShellFile.test.js

? isShellFile (7ms)

● isShellFile

expect(received).toBeTruthy()

^^^

Received: undefined

3 | test('isShellFile', () => {

4 |

> 5 | expect(isShellFile('bash.sh')).toBeTruthy()

| ^

6 | })

又報錯了,但這次報錯原因跟上次不同,說明有進步。

這次報錯原因是,期望函數調用返回值為真 , 但實際沒有返回真 。

這是當然的,因為在源文件中,根本沒有寫返回語句。

為了讓測試通過,修改 src/isShellFile.js

module.exports = function(filename) {

+ return true

}

運行 yarn test , 測試通過了!

PASS test/isShellFile.test.js

? isShellFile (3ms)

Test Suites: 1 passed, 1 total

Tests: 1 passed, 1 total

Snapshots: 0 total

Time: 1.548s

Ran all test suites.

把上述修改,提交到版本控制系統中。

git add package.json yarn.lock src test

git commit -m 'feat: init jest test case'

第二個用例

觀察我們的測試用例,發現太簡單了,只有正面的用例,沒有反面的、異常的用例

test('isShellFile', () => {

expect(isShellFile('bash.sh')).toBeTruthy()

})

在 test/isShellFile.test.js 添加一個反面的用例

test('isShellFile', () => {

expect(isShellFile('bash.sh')).toBeTruthy()

+ expect(isShellFile('bash.txt')).toBeFalsy()

})

運行 yarn test

(可以發現,在開發過程中需要反復執行上述命令,有個偷懶的辦法,執行yarn test --watch,即可監聽文件變化,自動執行測試用例)

FAIL test/isShellFile.test.js

? isShellFile (6ms)

● isShellFile

expect(received).toBeFalsy()

^^^

Received: true

4 |

5 | expect(isShellFile('bash.sh')).toBeTruthy()

> 6 | expect(isShellFile('bash.txt')).toBeFalsy()

| ^

7 | })

報錯了,期望返回假,但函數返回的是真。這是因為,源文件中, isShellFile 函數永遠返回真!

完善 src/isShellFile.js 邏輯

module.exports = function(filename) {

- return true;

+ return filename.indexOf('.sh') > -1

};

測試通過了

PASS test/isShellFile.test.js

? isShellFile (4ms)

Test Suites: 1 passed, 1 total

Tests: 1 passed, 1 total

Snapshots: 0 total

Time: 1.568s

Ran all test suites.

把上述修改提交到版本控制系統

git commit -am 'fix: 函數永遠返回真的bug'

第三個用例

我們再添加一個用例,這次考慮特殊情況: .sh 這種文件,不算是shell文件。

修改 test/isShellFile.test.js

expect(isShellFile("bash.sh")).toBeTruthy();

expect(isShellFile("bash.txt")).toBeFalsy();

+ expect(isShellFile('.sh')).toBeFalsy()

測試不通過

FAIL test/isShellFile.test.js

? isShellFile (8ms)

● isShellFile

expect(received).toBeFalsy()

^^^

Received: true

5 | expect(isShellFile("bash.sh")).toBeTruthy();

6 | expect(isShellFile("bash.txt")).toBeFalsy();

> 7 | expect(isShellFile('.sh')).toBeFalsy()

| ^

8 | });

說明邏輯待完善,修改 src/isShellFile.js

module.exports = function(filename) {

- return filename.indexOf(".sh") > -1;

+ let index = filename.indexOf(".sh");

+ return index > -1 && index != 0;

};

測試通過(為精簡文章內容,后面不再展示測試通過的輸出),提交代碼。

git commit -am 'fix: .sh應該返回false'

第四個用例

按照第三個用例的邏輯, .bash.sh 也不應該是shell文件,那么函數是否能正確判斷呢,測試便知。

修改 test/isShellFile.test.js

expect(isShellFile('.sh')).toBeFalsy()

+ expect(isShellFile('.bash.sh')).toBeFalsy()

測試不通過

FAIL test/isShellFile.test.js

? isShellFile (3ms)

● isShellFile

expect(received).toBeFalsy()

^^^

Received: true

6 | expect(isShellFile("bash.txt")).toBeFalsy();

7 | expect(isShellFile('.sh')).toBeFalsy()

> 8 | expect(isShellFile('.bash.sh')).toBeFalsy()

| ^

9 | });

說明邏輯待完善,修改 src/isShellFile.js

module.exports = function(filename) {

let index = filename.indexOf(".sh");

- return index > -1 && index != 0;

+ return !filename.startsWith('.') && index > -1;

};

測試通過,提交代碼。

git commit -am 'fix: .開頭的文件不算sh文件'

第五個用例

再考慮一種情況,如果 .sh 出現在中間呢?如 bash.sh.txt , 它不應該是shell文件,來看看函數是否能通過測試。

修改 test/isShellFile.test.js

expect(isShellFile('.bash.sh')).toBeFalsy()

+ expect(isShellFile('bash.sh.txt')).toBeFalsy()

測試不通過

FAIL test/isShellFile.test.js

? isShellFile (5ms)

● isShellFile

expect(received).toBeFalsy()

^^^

Received: true

7 | expect(isShellFile('.sh')).toBeFalsy()

8 | expect(isShellFile('.bash.sh')).toBeFalsy()

> 9 | expect(isShellFile('bash.sh.txt')).toBeFalsy()

| ^

10 | });

說明邏輯待完善,修改 src/isShellFile.js

module.exports = function(filename) {

- let index = filename.indexOf(".sh");

- return !filename.startsWith('.') && index > -1;

+ let index = filename.lastIndexOf(".");

+ return !filename.startsWith('.') && filename.substr(index) == '.sh';

};

測試通過,提交代碼。

git commit -am 'fix: .sh必須在結尾'

重構

我們來觀察目前 src/isShellFile.js 的函數邏輯

module.exports = function(filename) {

let index = filename.lastIndexOf(".");

return !filename.startsWith('.') && filename.substr(index) == '.sh';

};

對于 .bashrc 這樣的文件,并不是shell文件,因為它是以 . 開頭的。

則通過 filename.startsWith('.') 判斷即可,前面的函數調用 filename.lastIndexOf(".") 是多余的。也即,目前的函數判斷邏輯不夠簡明。

下面是一種優化思路:

module.exports = function(filename) {

return !filename.startsWith('.') && filename.substr(filename.lastIndexOf(".")) == '.sh';

};

測試通過,提交代碼

git commit -am 'refactor: 優化邏輯'

注意,這個重構示例的重點是:先完成功能,再重構

重構必須要有測試用例,且確保重構后全部測試用例通過

至于其他方面,見仁見智,并不是重點。

結論

本文通過代碼實例,踐行了測試先行的理念。

文中的代碼實現不是重點,而是開發過程。

文中 文件初始化 及 第一個用例 的內容,尤其值得回味,它體現了兩個思路:總是在有一個失敗的單元測試后才開始編碼

用必要的最小代碼讓測試通過

總的來看,TDD總是處于一個循環中:編寫用例

測試失敗

編寫代碼

測試成功

提交代碼

重復以上

通過這樣,功能的實現每次都是最小成本的,功能也是有步驟地、通過迭代完成的,而不是一步登天。

更關鍵的是,完善的測試用例,是開發者的“守護天使”,有了它們,以后在添加新功能時,修改/重構代碼都有了可靠的保障,讓開發者可以充滿信心,code with confidence !

擴展

使用babel

要想使用import/export語法,需要安裝babel相關依賴安裝依賴

yarn add --dev babel-jest @babel/core @babel/preset-env在項目根路徑新增配置文件 babel.config.js

module.exports = {

presets: [

[

'@babel/preset-env',

{

targets: {

node: 'current',

},

},

],

],

};重新啟動測試

yarn test --watch

為什么使用jest

因為這是vue官方工具鏈的一部分, 同時也可以為后續的組件測試作準備。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/530309.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/530309.shtml
英文地址,請注明出處:http://en.pswp.cn/news/530309.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql sqlstate 08001_關于Toad連接DB2的sqlstate=08001錯誤

新裝的centos6.3db29.7,數據庫導入完了的之后用Toad連接訪問之的時候出錯了。DB2 Database Error: ERROR [08001] [IBM] SQL30081N A communication error has been detected. Communication protocol being used: "TCP/IP". Communication API being use…

mysql 設置主鍵命令_MySQL常用命令

1、修改MySQL密碼方法一:use mysql;update user set passwordPASSWORD(“123456”) where user‘root’;flush privileges;忘記密碼:sed -ri 3d skip-grant-tables /etc/my.cnfsystemctl restart mariadbuse mysql&…

python 整除的數組_計算和可被整除的所有子數組

在我學習面試的時候,我在GeeksForGeeks上找到了這個問題和解決方案,但不明白答案。在上面說的是Let there be a subarray (i, j) whose sum is divisible by ksum(i, j) sum(0, j) - sum(0, i-1)Sum for any subarray can be written as q*k rem where…

java ha_java – Haproxy Bad Gateway 502

所以我在Jetty servlet面前使用HAProxy.目前的目標只是在配置完所有內容后進行概念驗證,加載和壓力測試.但是我在配置haproxy時遇到問題.我知道這不是我的應用程序的問題,因為我有運行nginx(tengine),一切正常.所以它必須與haproxy配置或haproxy工作的方式不適合我的需要.所以我…

java ioutils_java – 無法解析符號’IOUtils’

我使用以下代碼在我的Android應用程序中創建一個臨時文件:public File streamToFile (InputStream in) throws IOException {File tempFile File.createTempFile("sample", ".tmp");tempFile.deleteOnExit();FileOutputStream out new FileOu…

java const關鍵字_const關鍵字:終于擁有真正的常量聲明語句

你好,今天大叔想和你嘮扯嘮扯 ES6 新增的關鍵字 —— const。在說 const 關鍵字之前,大叔先和你嘮嘮大叔自己對 const 的感受 —— JavaScript 尼瑪終于可以聲明真正的常量啦!大叔為啥會發出這樣滴感嘆?實在是“天下苦秦久矣”呀~…

workerman高并發異步mysql_workerman怎么實現高并發

并發概念太模糊,這里以兩種可以量化的指標并發連接數和并發請求數來說明。并發連接數是指服務器當前時刻一共維持了多少TCP連接,而這些連接上是否有數據通訊并不關注。 (推薦學習: workerman教程)例如一臺消息推送服務器上可能維持了百萬的設…

checkout 撤銷修改_Git的4個階段的撤銷更改

雖然git誕生距今已有12年之久,網上各種關于git的介紹文章數不勝數,但是依然有很多人(包括我自己在內)對于它的功能不能完全掌握。以下的介紹只是基于我個人對于git的理解,并且可能生編硬造了一些不完全符合git說法的詞語。目的只是為了讓git通…

移除Java對象中的屬性_在java對象中添加和刪除屬性

我怎樣才能在 java中實現這一點.我有一個具有屬性的對象.public class Object {private final Credentials Credentials;private final int PageSize;private final int PageStart;private final int DefaultFilterId;public Object(Credentials Credentials, int PageSize, in…

java軟件開發ea介紹_開發說明 — Eacloud 1.0 documentation

PHP 代碼示例( Linux 版)解壓后,參考 phplinux/v3.4.0.1/文檔/PHP版服務器端工具包(Linux版)軟件使用手冊.pdfDemo 運行1.安裝對應版本的 PHP2.安裝運行時環境(glibc 庫等)3.修改 PHP 的配置文件 php.ini修改 php.ini,使 php 允許加載擴展,并…

java中operationBox_Java使用PDFBox開發包實現對PDF文檔內容編輯與保存

pdfbox開發包下載地址:http://pdfbox.apache.org/程序實現了PDF文檔的創建,讀入,與修改PDF內容并保存。可能有個前提,PDF文檔不是加密的,如果加密怎么辦,我沒研究過!源代碼如下:pack…

java訪問權限最高_java 訪問權限

Java語言中的訪問權限修飾符有4種,但是僅有3個關鍵字,因為不寫訪問權限,在Java中被稱為默認權限,或同包權限,本文中以(default)代替。下面按照權限從小到大的順序對4中訪問權限分別介紹。class我個人,我有很…

java中 queryparam_java – 何時使用@QueryParam和@PathParam

我不是問這里已經問過的問題:What is the difference between PathParam and QueryParam這是一個“最佳實踐”或常規問題。什么時候使用PathParam和QueryParam。我可以想到的是,決定可能使用兩者來區分信息模式。讓我在下面說明我的LTPO – 不完美的觀察…

java中fork函數_java中的forkjoin框架的使用

fork join框架是java 7中引入框架,這個框架的引入主要是為了提升并行計算的能力。fork join主要有兩個步驟,第一就是fork,將一個大任務分成很多個小任務,第二就是join,將第一個任務的結果join起來,生成最后…

Java h264起始碼_h.264 – 使用H264視頻的起始碼

有兩種H.264流格式,有時也稱為>附件B(在原始H.264流中找到)> AVCC(在像MP4這樣的容器中找到)H.264流由NAL(包裝單位)組成(1)附件B:在每個NAL單元的字節[x00] [x00] [x00] [x01]之前有4字節的起始碼.[start code]--[NAL]--[start code]--[NAL] etc(2)AVCC&…

java中已定義類型car_Java 8 習慣用語(8):Java 知道您的類型

Java?8是第一個支持類型推斷的 Java 版本,而且它僅對 lambda 表達式支持此功能。在 lambda表達式中使用類型推斷具有強大的作用,它將幫助您做好準備以應對未來的 Java版本,在今后的版本中還會將類型推斷用于變量等更多可能。這里的訣竅在于恰…

ATM柜員機JAVA課程設計_ATM柜員機學年論文設計(Java課程設計)

內容簡介:ATM柜員機學年論文設計(Java課程設計),共23頁,4599字,附源程序。一. 程序介紹3二. 開發環境搭建31. MyEclipse 5.5.1 GA安裝32. MyEclipse Designer 圖形設計插件安裝33. MySQL數據庫安裝4三&…

mysql 結果集什么意思_結果集中的mysql“和”邏輯

假設我有一個類似以下的數據集:table fooid | employeeType | employeeID-------------------------1 | Developer | 12 | Developer | 23 | Developer | 34 | Manager | 15 | Manager | 46 | Manager | 57 | CEO | 18 | CEO | 6我想運行一個查詢,該查詢將返回所有e…

opencv java 去干擾_java - OpenCV Java修補圖像格式要求 - 堆棧內存溢出

一直試圖讓修復工作在Android上進行,int height (int) viewMat.size().height;int width (int) viewMat.size().width;Mat maskMat new Mat();maskMat.create(viewMat.size(), CvType.CV_8U);maskMat.setTo(bColor);Point r1 new Point(width/2-width/10, heigh…

java中 set集合_第8篇 Java中的集合(Set)

Java 集合的 Set 接口Set類型與List類型的區別Set: 無序、不可重復List: 有序、可重復1、HashSetHashSet的存儲結構:HashMap特點:HashSet通過比較存放的哈希碼(hashCode)來確定對象存放的位置當兩個對象的哈希值相等時&#xff0c…