前几天突然了解到了jest单元测试,感觉挺有趣的,就趁机学一把,哈哈,我用其测试了我写的后台管理系统,大致了解了jest的使用,以及学习过程中学到的常用知识和在测试的过程中遇到的一些问题,我总结一下
Jest是 Facebook 的一套开源的 JavaScript 测试框架, 它自动集成了断言、JSDom、覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的测试框架。它能支持很多框架,比如 Babel、TypeScript、Node、React、Angular、Vue 等诸多框架。
(1)执行安装命令
vue中使用jest,其实并没有我们想象的那么复杂,之前我使用jest的时候,查了较多资料,也配置了许多设置,繁忙且繁琐,直到最后我才发现,原来仅仅只需要执行一句指令即可
vue add @vue/cli-plugin-unit-jest
这个命令会帮我们把相关的配置都配好,相关的依赖都装好,还会帮我们生成一个jest.config.js文件。
(2)jest中常用的一些配置项的介绍
module.exports = {
"moduleFileExtensions": [ //不需要配置
"js",
"json",
// 告诉 Jest 处理 `*.vue` 文件
"vue"
],
testMatch: [ //test文件所在位置
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
"transform": { //不需要配置
// 用 `vue-jest` 处理 `*.vue` 文件
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",
// 用 `babel-jest` 处理 js
"^.+\\.js$": "babel-jest"
},
"moduleNameMapper": { //不需要配置
"^@/(.*)$": "<rootDir>/src/$1"
},
"collectCoverage": true, //是否创建报告
"collectCoverageFrom": ["**/*.{js,vue}", "!**/node_modules/**"], //创建报告的文件来源
"coverageReporters": ["html", "text-summary"] //报告的格式
"coveragePathIgnorePatterns":"[]" //生成报告需要忽略的文件,默认值为 node_modules
"globals":{ //配置全局变量,此处我配置了一个全局变量VUE_APP_DATA,也可以在setup file中配置,如下说的lodash
"VUE_APP_DATA": {siteENV:'DEV'}}
setupFiles: ['<rootDir>/src/jest-setup.js'] //启动jest需要的文件
};
(3)在项目目录中创建tests文件,再创建unit文件,在其中文件命名的话,就以 xxx.spec.js命名(这个执行命令的时候,已经给我们创建了)
import { shallowMount } from '@vue/test-utils'
import explame from '@/components/Explame'
describe('Explame .vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message'
const wrapper = shallowMount(Explame , {
propsData: { msg }
})
expect(wrapper.text()).toMatch(msg)
})
})
(4)在package.json 中添加启动命令,然后通过在控制台执行npm run test:unit ,进行测试
Scripts配置:
"test:unit": "vue-cli-service test:unit"
(1)Jest 支持三种方式写测试代码
(2)测试结构
describe('add的方法测试',()=>{
test('2+3应该等于5',()=>{
expect(add(2,3)).toBe(5)
})
})
(3)mock方法和 处理
(4)覆盖率指标
在package.json中 设置 --coverage 即可 测试覆盖率
"test:unit": "vue-cli-service test:unit --coverage"

配置好后,会生成一个coverage文件

然后打开里面的index.html 里面会有详细的信息展示

三种颜色分别代表不同比例的覆盖率(<50%红色,50%~80%灰色, ≥80%绿色)
旁边显示的1x代表执行的次数

好的测试覆盖率标准
80%以下不及格,90%以上可以使用,95%以上优秀
--mount: 创建一个包含被挂载和渲染的 Vue 组件的 wrapper,它仅仅挂载当前实例
---shallowMount:和 mount 一样,创建一个包含被挂载和渲染的 Vue 组件的 Wrapper,只挂载一个组件而不渲染其子组件 (即保留它们的存根),这个方法可以保证你关心的组件在渲染时没有同时将其子组件渲染,避免了子组件可能带来的副作用(比如Http请求等)
---shallowMount和mount的区别:在文档中描述为"不同的是被存根的子组件",大白话就是shallowMount不会加载子组件,不会被子组件的行为属性影响该组件。
为什么使用shallowMount而不使用mount?
---我认为单元测试的重点在"单元"二字,而不是"测试",想测试子组件再为子组件写对应的测试代码即可
---Wrapper:常见的有一下几种方法
<template>
<div class="jest">
<div class="name">{{name}}</div>
<div class="name">{{name}}{{text}}</div>
<div class="text" @click="add">{{text}}</div>
</div>
</template>
<script src="./script.js">
export default {
name:"Foo",
props:{
name:{
type: String,
default: '啦啦啦'
}
},
data() {
return {
text: 123
}
},
methods:{
add(){
this.text += 1
}
}
}
</script>
开始测试
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
describe('Foo', () => {
const wrapper = shallowMount(Foo)
console.log(Wrapper.classes()) //['jest']
console.log(Wrapper.classes('jest')) //true
console.log(Wrapper.find('.name').text()) // 切记如果是类的话,要加点 : 啦啦
console.log(Wrapper.findAll('.name')) //返回dom数组 WrapperArray { selector: '.name' }
console.log(Wrapper.findAll('.name').at(0)) //取dom数组中的第一个
Wrapper.setData({text : 3}) // 设置一个值
console.log(Wrapper.vm.text) // 3
Wrapper.setProps({name : "拉拉"})
console.log(Wrapper.vm.name) //这个结果仍 为 啦啦啦
Wrapper.find('.text').trigger("click")
console.log(Wrapper.vm.text) // 4
})
也可以初始化某些数据
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
const wrapper = shallowMount(Foo,{
data() {
return {
bar: 'lala'
}
},
propsData:{
message: 'dd'
},
mocks: {
$route: {
query: {
aaa: '1',
}
},
$router: {
push: jest.fn(),
replace: jest.fn(),
}
}
})
describe('Foo', () => {
expect(2 + 2).toBe(4)
expect(null).toBeNull()
expect(undefined).toBeUndefined()
let a = 1;
expect(a).toBeDefined()
a = 'ada';
expect(a).toBeNaN()
a = true;
expect(a).toBeTruthy()
a = false;
expect(a).toBeFalsy()
a = [1,2,3];
expect(a).toContain(2)
expect(a).toHaveLength(3)
a = {a:1};
expect(a).toEqual({a:1})
})
(1)解决国际化i18n 的报错
Vue warn]: Error in config.errorHandler: "TypeError: _vm.$t is not a function"
import {shallowMount, mount, createLocalVue } from '@vue/test-utils'; // 引入 createLocalVue
import VueI18n from 'vue-i18n'; // 引入 第三方库
import enLocale from 'element-ui/lib/locale/lang/en'; // 以及自己配置的语言啦
import zhLocale from 'element-ui/lib/locale/lang/zh-CN';
import zhmsg from '../../public/lang/zh.json';
import enmsg from '../../public/lang/en.json';
const localVue = createLocalVue() // 创建临时的vue 实例
localVue.use(VueI18n)
const messages ={
en:{
...enmsg,
...enLocale
},
zh:{
...zhmsg,
...zhLocale
}
}
var i18n = new VueI18n({
locale:'zh',
message,
})
window.Languages=i18n
var Wrapper =shallowMount(XX(组件名),{
localVue,
// 用mock模拟
mocks:{
$t :(a,b)=>i18n.t(a,b) // 解决报错
}
})
(2)引入了Element ui ,Element 组件会报错,提示没有注册,比如HelloWorld 组件中使用到了el-button组件,就会报错。 解决的话,还是创建一个vue的临时实例,将其挂载上去
建立一个文件jest.setup.js(方便之后其他测试文件使用)
import { config,createLocalVue } from '@vue/test-utils';
import ElementUI from 'element-ui';
const testVue = createLocalVue();
testVue.use(ElementUI);
export const localVue = testVue;
HelloWorld的测试文件使用
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld'
import {localVue} from '@/jest-setup'
describe('HelloWorld.vue', () => {
it('renders component', () => {
// 将其传进去
const wrapper = shallowMount(HelloWorld, {localVue})
expect(wrapper.findAll('.hello-world').length).toBe(1)
})
})
这就是我所学到的jest单元测试方面的知识,之后在工作中如果遇到了jest方面新的问题,我会不断进行更新与完善,有句话说的好,“时人不识凌云木,直待凌云始道高”
一起加油吧,程序猿!
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我在app/helpers/sessions_helper.rb中有一个帮助程序文件,其中包含一个方法my_preference,它返回当前登录用户的首选项。我想在集成测试中访问该方法。例如,这样我就可以在测试中使用getuser_path(my_preference)。在其他帖子中,我读到这可以通过在测试文件中包含requiresessions_helper来实现,但我仍然收到错误NameError:undefinedlocalvariableormethod'my_preference'.我做错了什么?require'test_helper'require'sessions_hel
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您