在我以前的
javascript fullstack
項(xiàng)目中,單元測試一直是分裂的,react
前端用jest,node.js
后端用mocha。由于在前端使用jest
時(shí),所體會(huì)到的簡潔,讓我一直有沖動(dòng)想用jest
來一統(tǒng)江湖。在最近的一個(gè)項(xiàng)目中,我做到了,對比mocha
,我有下面一些體會(huì)。
配置簡潔
jest
幾乎是可以零配置的。它會(huì)自動(dòng)識別一些常用的測試文件pattern,比如__test__
、*.spec.js
、 *.test.js
等。我的nodejs項(xiàng)目的配置文件只有下面幾行,下面是指package.json
文件:
"scripts": {
"test": "jest"
},
"jest": {
"testEnvironment": "node"
}
testEnvironment
這個(gè)配置是對于nodejs項(xiàng)目是必須的,如果不配置,在async的單元測試中如果拋出異常,則系統(tǒng)不會(huì)立刻停止,而只會(huì)超時(shí),并且不會(huì)定位錯(cuò)誤位置。
配置完后,就可以用yarn run test
來運(yùn)行測試了。
測試代碼簡潔
- 在
mocha
中我們必須要describe
,比如:
descibe('suiteA', () => {
before(() => {})
it('testA', () => {
})
it('testA', () => {
})
)
可是文件已經(jīng)把一個(gè)個(gè)suite
分開,為什么還要describe
,所以jest
可以省略describe
,如下:
beforeAll(() => {})
it('testA', () => {
})
it('testA', () => {
})
-
jest
幾乎內(nèi)置了所有單元測試需要的庫,比如mock
和expect
,無需像mocha
一樣需要引入一堆。
易于和babel集成
為了能使用更多的純nodejs
暫時(shí)不支持的語法(比如:import
),越來越多的nodejs
項(xiàng)目使用babel
來編譯項(xiàng)目。在jest
中支持babel
只需要安裝jest-babel
,即運(yùn)行:yarn add jest-babel
。
內(nèi)置豐富的expect
而jest
內(nèi)置expect
,甚至比chai
[1]更豐富,比如:
- 支持snapshot,這個(gè)是
jest
的killing feature
比如我們要寫一個(gè)JSON轉(zhuǎn)XML函數(shù)jsonToXml: string => string
,而且輸入和輸出都相對長,我們可能會(huì)這樣寫測試用例:
it('make sure transform works', () => {
const input = `{
"name": "ron",
"job": "programmer",
"tags": ["javascript", "functional programming"],
}`
const expectedOutput = `
<user><name>ron</><job>programmer<job/><tags><tag>javascript</tag><tag>functional programmer</tags></tags></user>
`
expect(jsonToXml(input)).toEqual(expectedOutput)
})
請問此時(shí)你的眼睛花了沒?更麻煩的是,當(dāng)要修改函數(shù)時(shí),所有的校對又要重新來一遍。
jest
針對這種場景提出了更好的解決方案snapshot
,上面的用例可以這樣寫:
it('make sure transform works', () => {
const input = `{
"name": "ron",
"job": "programmer",
"tags": ["javascript", "functional programming"],
}`
expect(jsonToXml(input)).toMatchSnapshot()
})
其原理就是,jest
會(huì)把需要expect
的內(nèi)容(即expected result)自動(dòng)保存到一個(gè)自動(dòng)生成的文件中,在以后每次運(yùn)行測試用例時(shí)都會(huì)比較以前保存的內(nèi)容。如果修改了函數(shù),則測試用例會(huì)fail,但若確定這是by design
,則可以運(yùn)行jest -u
來更新自動(dòng)保存的文件。
- 更好地對promise的支持,特別是對
reject
的支持
it('fetchData() rejects to be error', () => {
// make sure to add a return statement
return expect(Promise.reject('octopus')).rejects.toBeDefined();
});
test('fetchData() rejects to be error', async () => {
const drinkOctopus = new Promise(() => {
throw new DisgustingFlavorError('yuck, octopus flavor');
});
await expect(drinkOctopus).rejects.toMatch('octopus');
});
- 其它還有比如:
expect.objectContaining
、expect.arrayContaining
等
webstorm已經(jīng)支持jest
之前,我沒有轉(zhuǎn)jest
的一個(gè)很重要的原因是webstorm
不支持,不過在2017.1的版本中已經(jīng)支持jest
了。
jest還在頻繁地更新中
mocha
似乎已經(jīng)處于維護(hù)階段,而jest
還在高頻地開發(fā)中,一定會(huì)迭代出更多的新功能。
總結(jié)
在我遷移的這2個(gè)月中,jest
讓我可以更簡潔地測試,并沒有感覺到用什么mocha
可以做,而jest
不能做或者做起來比較困難的。我想是時(shí)候和陪伴了我多年的mocha
說bye bye
了。
-
一個(gè)專門的
assert
庫,mocha
不內(nèi)置expect
,因此一般使用mocha
時(shí)會(huì)使用chai
?