前端組件的測試

爲解放勞動力,發展生產力css

測試有了這般變化:

鼠標點擊手動測試 -> 用腳本模擬,自動化測試html

Vue中的組件測試

須要安裝的包

  1. 全局安裝:babel、mocha、karma
  2. 其餘局部安裝的包在下面的【測試環境搭建】最下方配置文件中給出

測試環境搭建

配置主要是兩個,一是 karma 的配置文件,另外一個是 karma 須要的webpack 配置文件。vue

webpack 的配置文件是爲了解析那些須要測試的源文件(vue 相關的文件),而後再給karma 的單元測試用例去識別。node

webpack3 配置文件

var path = require("path")
var webpack = require("webpack")
var ExtractTextPlugin = require('extract-text-webpack-plugin')

function resolve(dir) {

    return path.join(__dirname, '..', dir)
}

var webpackConfig = {

    module: {

        rules: [

            // babel-loader
            {
                test: /\.js$/,
                use: 'babel-loader',
                include: [resolve('src'), resolve('test')]
            },

            // 爲了統計代碼覆蓋率,對 js 文件加入 istanbul-instrumenter-loader
            {
                test: /\.(js)$/,
                exclude: /node_modules/,
                include: /src|packages/,
                enforce: 'post',
                use: [{
                    loader: "istanbul-instrumenter-loader",
                    options: {
                        esModules: true
                    },
                }]
            },

            // vue loader
            {
                test: /\.vue$/,
                use: [{
                    loader: 'vue-loader',
                    options: {
                        // 爲了統計代碼覆蓋率,對 vue 文件加入 istanbul-instrumenter-loader
                        preLoaders: {
                            js: 'istanbul-instrumenter-loader?esModules=true'
                        }
                    }
                }]
            },

            // css loader
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',
                    fallback: 'vue-style-loader'
                })
            },

            // img loader
            {
                test: /\.(png|gif|jpe?g)(\?\S*)?$/,
                use: [{loader: 'url-loader'}]
            },

            // font loader
            {
                test: /\.(eot|woff|woff2|ttf|svg)(\?\S*)?$/,
                use: [{loader: 'url-loader'}]
            },
        ]
    },

    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.esm.js',
            '@': resolve('src'), // 調用組件的時候方便點
        }
    },

    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"'
            }
        })
    ]
}

module.exports = webpackConfig

karma配置文件

有兩種方法:webpack

  1. cd進入當前項目,使用 karma init命令,而後一系列提示選擇...
  2. 不用 karma init命令,新建一個karma.conf.js文件,而後配置:
var webpackConfig = require('../../build/webpack.test.config');

module.exports = function (config) {
    config.set({
        // to run in additional browsers:
        // 1. install corresponding karma launcher
        //    http://karma-runner.github.io/0.13/config/browsers.html
        // 2. add it to the `browsers` array below.
        browsers: ['PhantomJS'],
        frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
        reporters: ['spec', 'coverage'],
        files: ['index.js'],
        preprocessors: {
            './index.js': ['webpack', 'sourcemap']
        },

        webpackMiddleware: {
            noInfo: true
        },
        // 不顯示 `webpack` 打包日誌信息
        webpackServer: {
            noInfo: true
        },
        webpack: webpackConfig,
        coverageReporter: {
            dir: './coverage',
            reporters: [
                { type: 'lcov', subdir: '.' },
                { type: 'text-summary' }
            ]
        }
    })
}

目錄結構

├─build 
│      webpack.test.config.js
│
├─src 
│
├─package.json
│
└─test 
      └─unit
          │  index.js
          │  karma.config.js
          │
          ├─coverage
          │
          └─specs
               *.spec.js

測試文件相關都放置在 test/unit 下,入口文件爲 index.js,每一個vue 組件對應的測試用例名爲組件名稱.spec.js,根據 istanbul-instrumenter-loader 文檔的說明,測試總入口文件 index.js 內容以下:git

import Vue from 'vue'

Vue.config.productionTip = false

// 測試全部以 .spec.js 名稱結尾的文件
// require all test files (files that ends with .spec.js)
const testsContext = require.context('./specs', true, /\.spec$/)
testsContext.keys().forEach(testsContext)

// 要求除main.js以外的全部src文件進行覆蓋
// require all src files except main.js for coverage.
// you can also change this to match only the subset of files that
// you want coverage for.
const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/)
srcContext.keys().forEach(srcContext)

最後看下package.json的devDependencies

"devDependencies": {

    ...

    "babel-core": "^6.9.0",
    "babel-loader": "^7.1.1",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-plugin-transform-vue-jsx": "^3.3.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-stage-2": "^6.18.0",
    "babel-runtime": "^6.18.0",
    "chai": "^4.1.2",
    "chalk": "^2.0.1",
    "css-loader": "^0.28.4",
    "extract-text-webpack-plugin": "^2.1.2",
    "istanbul-instrumenter-loader": "^3.0.0",
    "karma": "^1.7.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.4",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.2",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "^2.0.4",
    "mocha": "^3.5.0",
    "phantomjs-prebuilt": "^2.1.15",
    "postcss-px2rem": "^0.3.0",
    "sinon": "^3.2.1",
    "sinon-chai": "^2.13.0",

    ...

    "style-loader": "^0.18.2",
    "url-loader": "^0.5.7",
    "vue-loader": "^13.0.4",
    "vue-router": "^2.7.0"
  },

執行命令 sudo npm install 安裝所須要的包github

注意:web

當流程走到下面這個步驟時,可能耗費的時間比較長,千萬別ctrl + c中斷下載從新install,靜靜等待就好vue-router

donnot.png

開始測試

  1. 新建一個Hello.vue組件npm

    <template>
        <div>msg</div>
     </template>
     <script>
     export default {
       name: 'hello',
       data () {
         return {
           msg: 'Welcome to Your Vue.js App'
         }
       }
     }
     </script>
  2. test/unit/specs 目錄下建立一個 Hello.spec.js 文件,再寫個簡單的單元測試用例:

    import Vue from 'vue'
    import Hello from '@/components/Hello'
    
    describe('Hello.vue', () => {
      it('should render correct contents', () => {
        const Constructor = Vue.extend(Hello)
        const vm = new Constructor().$mount()
        expect(vm.$el.querySelector('.hello h1').textContent)
          .to.equal('Welcome to Your Vue.js App')
      })
    })
  3. package.json文件配置:

    // package.json
      "scripts": {
         "test": "karma start test/unit/karma.config.js --single-run"
       }
  4. 執行npm run test輸出測試結果,同時在 test/unit/coverage 生成測試報告。

一些測試的Case

網上的例子...

點我點我點我

再點我點我點我

React中的組件測試

Jest + Enzyme

Jest:JS單元測試工具,包含DOM API 支持、斷言庫、Mock 庫等,還包含了 Spapshot Testing、 Instant Feedback 等特性

Enzyme:經過 jQuery 風格的方式進行DOM 處理,開發體驗十分友好

測試環境搭建

1. 安裝一些包

npm install jest enzyme babel-jest --save-dev

2. 在package.json中配置jest:

"jest": {
    "moduleFileExtensions": [
      "js",
      "jsx"
    ],
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      ".*\\.(css|less|scss)$": "<rootDir>/__mocks__/styleMock.js"
    },
    "transform": {
      "^.+\\.js$": "babel-jest"
    }
  },

3. 新增啓動測試的腳本:

"scripts": {
    "test": "jest"
  }

開始測試

1. 引入

import { shallow } from 'enzyme'

Enzyme 提供了三種方法

  • shallow:淺渲染。其做用是僅僅渲染至虛擬節點,不會返回真實的節點,能極大提升測試性能。可是它不適合測試包含子組件、須要測試聲明週期的組件
  • mount:Full Rendering,很是適用於存在於 DOM API 存在交互組件,或者須要測試組件完整的生命週期
  • render:Static Rendering,用於 將 React 組件渲染成靜態的 HTML 並分析生成的 HTML 結構

通常狀況下,shallow 就已經足夠用了,偶爾狀況下會用到 mount。

2. 模擬

const setup = () => {
  // 模擬 props
  const props = {
    // Jest 提供的mock 函數
    onAddClick: jest.fn()
  }

  // 經過 enzyme 提供的 shallow(淺渲染) 建立組件
  const wrapper = shallow(<AddTodoView {...props} />)
  return {
    props,
    wrapper
  }
}

3. 編寫Test Case

Case1::測試組件是否正常渲染

describe('AddTodoView', () => {
  const { wrapper, props } = setup();

  // case1
  // 經過查找存在 Input,測試組件正常渲染
  it('AddTodoView Component should be render', () => {
    //.find(selector) 是 Enzyme shallow Rendering 提供的語法, 用於查找節點
    // 詳細用法見 Enzyme 文檔 http://airbnb.io/enzyme/docs/api/shallow.html
    expect(wrapper.find('input').exists());
  })
})

Case2:輸入內容並敲下回車鍵,測試組件調用props的方法

it('When the Enter key was pressed, onAddClick() shoule be called', () => {
    // mock input 輸入和 Enter事件
    const mockEvent = {
      keyCode: 13, // enter 事件
      target: {
        value: 'Test'
      }
    }
    // 經過 Enzyme 提供的 simulate api 模擬 DOM 事件
    wrapper.find('input').simulate('keyup',mockEvent)
    // 判斷 props.onAddClick 是否被調用
    expect(props.onAddClick).toBeCalled()
  })

生成報告

Jest 還提供了生成測試覆蓋率報告的命令,只須要添加上 --coverage 這個參數既可生成

"scripts": {
    "coverage": "jest --colors --coverage"
  }

寫在最後

難點是要考慮周全,測試用例覆蓋全面

相關文章
相關標籤/搜索