前端自動化測試:Vue 應用測試
項目環(huán)境搭建
運行 vue create [project-name] 來創(chuàng)建一個新項目。選擇 "Manually selectfeatures" 和 "UnitTesting",以及 "Jest" 作為 test runner。
一旦安裝完成,cd 進入項目目錄中并運行 yarn test:unit。
通過 jest 配置文件:
\jest.config.js ==> node_modules\@vue\cli-plugin-unit-jest\jest-preset.js ==> \node_modules\@vue\cli-plugin-unit-jest\presets\default\jest-preset.js
jest-preset.js 文件就是 Vue 項目創(chuàng)建后,默認的 jest 配置文件:
- module.exports= {
- // 可加載模塊的后綴名
- moduleFileExtensions: [
- 'js',
- 'jsx',
- 'json',
- // tell Jest to handle *.vue files
- 'vue'
- ],
- // 轉換方式
- transform: {
- // process *.vue files with vue-jest
- // 如果.vue結尾的,使用vue-jest進行轉換
- '^.+\\.vue$': require.resolve('vue-jest'),
- '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
- require.resolve('jest-transform-stub'),
- '^.+\\.jsx?$': require.resolve('babel-jest')
- },
- // 轉換時忽略文件夾
- transformIgnorePatterns: ['/node_modules/'],
- // support the same @ -> src alias mapping in source code
- // webpack 的別名映射轉換
- moduleNameMapper: {
- '^@/(.*)$':'<rootDir>/src/$1'
- },
- // 指定測試環(huán)境為 jsdom
- testEnvironment:'jest-environment-jsdom-fifteen',
- // serializer for snapshots
- // 快照序列化器
- // 使用 jest-serializer-vue 進行組件快照的序列化方式
- // 就是將組件轉為字符串,后面進行快照測試時,就可以看到了
- snapshotSerializers: [
- 'jest-serializer-vue'
- ],
- // 測試代碼文件在哪里
- testMatch: [
- '**/tests/unit/**/*.spec.[jt]s?(x)',
- '**/__tests__/*.[jt]s?(x)'
- ],
- // https://github.com/facebook/jest/issues/6766
- testURL:'http://localhost/',
- // 監(jiān)視模式下的插件
- watchPlugins: [
- require.resolve('jest-watch-typeahead/filename'),
- require.resolve('jest-watch-typeahead/testname')
- ]
- }
快速體驗
默認測試用例:tests\unit\example.spec.js
- //tests\unit\example.spec.js
- // 導入組件掛載器,不用手動寫vue入口
- import { shallowMount } from'@vue/test-utils'
- // 導入要測試的組件
- import HelloWorld from'@/components/HelloWorld.vue'
- describe('HelloWorld.vue', () => {
- it('rendersprops.msg when passed', () => {
- const msg ='newmessage'
- const wrapper =shallowMount(HelloWorld, {
- props: { msg }
- })
- expect(wrapper.text()).toMatch(msg)
- })
- })
- $ npm runtest:unit
搭建完基本的 Vue 測試環(huán)境,在正式開始 Vue 測試之前,我們先了解一下測試開發(fā)的方法。
測試開發(fā)方式
測試不僅能夠驗證軟件功能、保證代碼質量,也能夠影響軟件開發(fā)的模式。
測試開發(fā)有兩個流派:
- TDD:測試驅動開發(fā),先寫測試后實現(xiàn)功能
- BDD:行為驅動開發(fā),先實現(xiàn)功能后寫測試
什么是TDD
TDD(Test-driven development),就是測試驅動開發(fā),是敏捷開發(fā)中的一項核心實踐和技術,也是一種軟件設計方法論。
它的原理就是在編寫代碼之前先編寫測試用例,由測試來決定我們的代碼。而且 TDD 更多地需要編寫獨立的測試用例,比如只測試一個組件的某個功能點,某個工具函數(shù)等。
TDD開發(fā)流程:
- 編寫測試用例
- 運行測試
- 編寫代碼使測試通過
- 重構/優(yōu)化代碼
- 新增功能,重復上述步驟
- // tests\unit\example.spec.js
- // 導入組件掛載器,不用手動寫vue入口
- import { shallowMount } from'@vue/test-utils'
- // 導入要測試的組件
- import HelloWorld from'@/components/HelloWorld.vue'
- import {add} from'@/utiles/math.js'
- // 輸入:1,2
- // 輸出:3
- test('sum', () => {
- expect(add(1,2)).toBe(3)
- })
單純運行測試代碼肯定報錯,有了測試代碼,為了通過測試,再具體寫 math 模塊中的 add() 方法:
- // math.js
- functionadd (a, b) {
- return a + b
- }
- exportdefault add
Vue 3 的 TDD 測試用例
src\components\TodoHeader.vue 組件內容
- <template>
- <header>
- <h1>Todos</h1>
- <input
- v-model="inputValue"
- placeholder="What needs to be done?"
- data-testid="todo-input"
- @keyup.enter="handleNewTodo"
- />
- </header>
- </template>
測試用例:
tests\unit\example.spec.js
- // 導入組件掛載器,不用手動寫vue入口
- import { shallowMount } from'@vue/test-utils'
- // 導入要測試的組件
- import HelloWorld from'@/components/HelloWorld.vue'
- import TodoHeader from'@/components/TodoHeader.vue'
- test('unit: new todo',async () => {
- const wrapper =shallowMount(TodoHeader) // 掛載渲染組件
- const input = wrapper.find('[data-testid="todo-input"]') // 查找input
- // 給input設置一個值
- const text ='helloworld'
- await input.setValue(text)
- // 觸發(fā)事件
- await input.trigger('keyup.enter')
- // =========
- // 以上是具體操作,輸入內容按下回車后,希望做什么?↓👇
- // =========
- // 驗證應該發(fā)布一個對外的 new-todo 的事件
- expect(wrapper.emitted()['new-todo']).toBeTruthy()
- // 驗證導出事件的參數(shù)是否是傳入的值
- expect(wrapper.emitted()['new-todo'][0][0]).toBe(text)
- // 驗證文本框內容是否清空
- expect(input.element.value).toBe('')
- })
src\components\TodoHeader.vue 組件內容
- exportdefault {
- data(){
- return {
- inputValue:''
- }
- },
- methods:{
- handleNewTodo(){
- if(this.inputValue.trim().length){
- // 發(fā)布對外的 new-todo 事件值為文本框輸入內容
- this.$emit('new-todo',this.inputValue)
- this.inputValue=''
- }
- }
- }
- };