单测(unit testing)

Jest

新建一个vue项目

vue create test-example
1、依赖安装

1、依赖安装vue-jest、Vue Test Utils、babel-jest、babel-preset-env

npm install --save-dev vue-jest Vue Test Utils babel-jest babel-preset-env

vue-jest:为了告诉 Jest 如何处理 *.vue 文件,我们需要安装和配置 vue-jest 预处理器

Vue Test Utils:官方vue测试辅助工具

babel-jest:在测试中让node支持es6转译

2、文件配置

scripts中添加测试命令
添加jest块,告诉jest要处理vue文件和遇到vue文件时候要使用vue-jest处理

// package.json
{
  "scripts": {
    "test": "jest"
  }
}

// package.json
{
  // ...
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      // 告诉 Jest 处理 `*.vue` 文件
      "vue"
    ],
    "transform": {
      // 用 `vue-jest` 处理 `*.vue` 文件
      ".*\\.(vue)$": "vue-jest"
    }
  }
}

如果你在 webpack 中配置了别名解析,比如把 @ 设置为 /src 的别名,那么你也需要用 moduleNameMapper 选项为 Jest 增加一个匹配配置:

{
  // ...
  "jest": {
    // ...
    // 支持源代码中相同的 `@` -> `src` 别名
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    }
  }
}

配置支持babel

{
  // ...
  "jest": {
    // ...
    "transform": {
      // ...
      // 用 `babel-jest` 处理 js
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    }
    // ...
  }
}

完整package.json配置文件如下:

{
  "name": "test-example",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:e2e": "vue-cli-service test:e2e",
    "test:unit": "vue-cli-service test:unit",
    "test": "jest"
  },
  "dependencies": {
    "core-js": "^3.3.2",
    "vue": "^2.6.10",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.0.0",
    "@vue/cli-plugin-e2e-cypress": "^4.0.0",
    "@vue/cli-plugin-unit-jest": "^4.0.0",
    "@vue/cli-service": "^4.0.0",
    "@vue/test-utils": "^1.0.0-beta.29",
    "babel-jest": "^24.9.0",
    "babel-preset-env": "^1.7.0",
    "jest": "^24.9.0",
    "vue-jest": "^3.0.5",
    "vue-template-compiler": "^2.6.10"
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {}
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ],
  "jest": {
    "preset": "@vue/cli-plugin-unit-jest",
    "moduleFileExtensions": [
      "js",
      "json",
      "vue"
    ],
    "transform": {
      ".*\\.(vue)$": "vue-jest",
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    },
    "moduleNameMapper": {
      "^@/(.*)$": "<rootDir>/src/$1"
    }
  }
}

测试vue组件实例

项目在git:https://github.com/lsx416010171/jest-example

import {mount} from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld'
import MyButton from '@/components/MyButton'
import Axios from '@/components/Axios'
import axios from 'axios'

describe('测试Vue组件实例',()=>{
    // 创建一个包含被挂载和渲染的 Vue 组件的 Wrapper
    const wapper = mount(HelloWorld)
    it('测试props',()=>{
        // 在创建的时候修改了props中msg的值
        wapper.setProps({ msg: 'HelloWorld' })
        expect(wapper.vm.msg).toBe('HelloWorld')
    })
    it('测试data',()=>{
        // 使用setData来修改原组件data的值
        wapper.setData({title : 'Im hello world in test'})
        expect(wapper.vm.title).toBe('Im hello world in test')
    })
    it('测试DOM',()=>{
        // 使用find来寻找dom中的元素
        // text 是dom元素中文本的内容
        expect(wapper.find('.hello h1').text()).toBe('HelloWorld')
        // is 判断元素tag标签
        expect(wapper.find('.hello h1').is('div'))
    })
})

describe('测试Vue组件实例',()=>{
    const wapper = mount(MyButton)
    it('测试自定义事件',()=>{
        // 创建mock函数
        const mockFn = jest.fn();
        // 设置 Wrapper vm 的方法并强制更新。
        wrapper.setMethods({
            increment: mockFn
        });
        // 模拟点击事件
        wapper.find('button').trigger('click');
        // 查看是否有回调
        expect(mockFn).toBeCalled();
        // 回调次数
        expect(mockFn).toHaveBeenCalledTimes(1)
    })
})

// 单元测试的核心之一就是测试方法的行为是否符合预期,在测试时要避免一切的依赖,将所有的依赖都mock掉。
// 第一步:不需要实际调用axios.get方法,需要将它mock掉
// 第二步:测试是否调用了axios方法(但是并不实际触发)并且返回了一个Promise对象
const mockData = {
    data: {
      code : 1,
      msg : 'sucess'
    }
  };
jest.mock('axios', () => ({
    get: jest.fn(() => Promise.resolve(mockData))
}));
describe('测试方法',()=>{
    beforeEach(() => {
        axios.get.mockClear();
        wrapper = shallow(Axios);
    });
    
    // 点击按钮后调用了 getAnswer 方法
    it('sendRequest Fn should be called', () => {
        const mockFn = jest.fn();
        wrapper.setMethods({sendRequest: mockFn});
        wrapper.find('button').trigger('click');
        expect(mockFn).toBeCalled();
    });
    
    // 点击按钮后调用了axios.get方法
    it('axios.get Fn should be called', () => {
        const URL = 'www.pokepe.vip/test';
        wrapper.find('button').trigger('click');
        expect(axios.get).toBeCalledWith(URL)
    });

    // 测试axios返回数据是否正确
    // 因为axios是异步的,所以我们也要异步监听数据,有几种方法用来处理异步问题
    // 1、done  2、async/await 3、Pomise

    // done
    // fetchData方法执行成功后,调用回调函数callback,遇到done才会结束
    it('Calls get promise result',async ()=> {
        function callback(data) {
          expect(data).toBe('peanut butter');
          done();
        }
        fetchData(callback);
    });

    // async/await 方法
    it('Calls get promise result',async ()=> {
        const result = await wrapper.vm.sendRequest()
        expect(result).toEqual(mockData)
    });

    // axios.get方法返回值(Promise)
    it('Calls get promise result', ()=> {
        return expect(wrapper.vm.sendRequest()).resolves.toEqual(mockData);
    });
})
Logo

前往低代码交流专区

更多推荐