原文链接:https://www.jianshu.com/p/38a37d5fccb2
视屏链接:https://www.bilibili.com/video/av54531291
在《前端进阶之路: 前端架构设计(3) - 测试核心》这边文章中, 通过分析了"传统手工测试的局限性" 去引出了测试驱动开发的理念, 并介绍了一些测试工具. 这篇文章我将通过一个Vue的项目, 去讲解如何使用mocha & karma, 且结合vue官方推荐的vue-test-utils去进行单元测试的实战.
一. 安装
我为本教程写一个示例库, 您可以直接跳过所有安装过程, 安装依赖后运行该示例项目:
如果想一步步进行安装, 也可以跟着下面的步骤进行操作:
(一) 使用脚手架初始化vue项目(使用webpack模板)
//命令行中输入(默认阅读该文章的读者已经安装vue-cli和node环境)vue init webpack vueunittest
注意, 当询问到这一步Pick a test runner(Use arrow keys)时, 请选择使用Karma and Mocha
选择Karma ad Mocha
接下来的操作进入项目npm install安装相关依赖后(该步骤可能更会出现PhantomJS这个浏览器安装失败的报错, 不用理会, 因为 之后我们不使用这个浏览器),npm run build即可.
(二) 安装Karma-chrome-launch
接下来安装karma-chrome-launcher, 在命令行中输入
npm install karma-chrome-launcher --save-dev
然后在项目中找到test/unit/karma.conf.js文件, 将PhantomJS浏览器修改为Chrome不要问我为什么不使用PhantomJS, 因为经常莫名的错误, 改成Chrome就不会!!!)
//karma.conf.jsvarwebpackConfig=require('../../build/webpack.test.conf')module.exports=function(config){config.set({//browsers: ['PhantomJS'],browsers:['Chrome'],...})}
(三) 安装Vue-test-utils
安装Vue.js 官方的单元测试实用工具库, 在命令行输入:
npm install--save-dev vue-test-utils
(四) 执行npm run unit
当你完成以上两步的时候, 你就可以在命令行执行npm run unit尝鲜你的第一次单元测试了, Vue脚手架已经初始化了一个HelloWorld.spec.js的测试文件去测试HelloWrold.vue, 你可以在test/unit/specs/HelloWorld.spec.js下找到这个测试文件.(提示: 将来所有的测试文件, 都将放specs这个目录下, 并以测试脚本名.spec.js结尾命名! )
在命令行输入npm run unit, 当你看到下图所示的一篇绿的时候, 说明你的单元测试通过了!
第一次单元测试测试通过
二. 测试工具的使用方法
下面是一个Counter.vue文件, 我将以该文件为基础讲解项目中测试工具的使用方法.
//Counter.vue
Counter.vue {{count}}自增
(一) Mocha框架
1. Mocha测试脚本的写法
Mocha的作用是运行测试脚本, 要对上面Counter.vue进行测试, 我们就要写测试脚本, 通常测试脚本应该与Vue组件名相同, 后缀为spec.js. 比如,Counter.vue组件的测试脚本名字就应该为Counter.spec.js
//Counter.spec.jsimportVuefrom'vue'importCounterfrom'@/components/Counter'describe('Counter.vue',()=>{it('点击按钮后, count的值应该为1',()=>{//获取组件实例constConstructor=Vue.extend(Counter);//挂载组件constvm=newConstructor().$mount();//获取buttonconstbutton=vm.$el.querySelector('button');//新建点击事件constclickEvent=newwindow.Event('click');//触发点击事件button.dispatchEvent(clickEvent);//监听点击事件vm._watcher.run();// 断言:count的值应该是数字1expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);})})
上面这段代码就是一个测试脚本.测试脚本应该包含一个或多个describe, 每个describe块应该包括一个或多个it块
describe块称为"测试套件"(test suite), 表示一组相关的测试. 它是一个函数, 第一个参数是测试套件的名称(通常写测试组件的名称, 这里即为Counter.js), 第二个参数是一个实际执行的函数.
it块称为"测试用例"(test case), 表示一个单独的测试, 是测试的最小单位. 它也是一个函数, 第一个参数是测试用例的名称(通常描述你的断言结果, 这里即为"点击按钮后, count的值应该为1"), 第二个参数是一个实际执行的函数.
2. Mocha进行异步测试
我们在Counter.vue组件中添加一个按钮, 并添加一个异步自增的方法为incrementByAsync, 该函数设置一个延时器, 1000ms后count自增1.
...自增 异步自增 ...
给测试脚本中新增一个测试用例, 也就是it()
it('count异步更新, count的值应该为1',(done)=>{///获取组件实例constConstructor=Vue.extend(Counter);//挂载组件constvm=newConstructor().$mount();//获取buttonconstbutton=vm.$el.querySelectorAll('button')[1];//新建点击事件constclickEvent=newwindow.Event('click');//触发点击事件button.dispatchEvent(clickEvent);//监听点击事件vm._watcher.run();//1s后进行断言window.setTimeout(()=>{// 断言:count的值应该是数字1expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);done();},1000);})
Mocha中的异步测试, 需要给it()内函数的参数中添加一个done, 并在异步执行完后必须调用done(), 如果不调用done(), 那么Mocha会在2000ms后报错且本次单元测试测试失败(mocha默认的异步测试超时上线为2000ms), 错误信息如下:
未调用done()的报错
3. Mocha的测试钩子
如果大家对于vue的mounted(),created()钩子能够理解的话, 对Mocha的钩子也很容易理解, Mocha在describe块中提供了四个钩子:before(),after(),beforeEach(),afterEach(). 它们会在以下时间执行
describe('钩子说明',function(){before(function(){// 在本区块的所有测试用例之前执行});after(function(){// 在本区块的所有测试用例之后执行});beforeEach(function(){// 在本区块的每个测试用例之前执行});afterEach(function(){// 在本区块的每个测试用例之后执行});});
上述就是Mocha的基本使用介绍, 如果想了解Mocha的更多使用方法, 可以查看下面的文档和一篇阮一峰的Mocha教程:
Mocha官方文档 :https://mochajs.org/
Mocha官方文档翻译 :http://www.jianshu.com/p/9c78548caffa
阮一峰 - 测试框架 Mocha 实例教程 :http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
(二) Chai断言库
上面的测试用例中, 以expect()方法开头的就是断言 .
expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);
所谓断言, 就是判断源码的实际执行结果与预期结果是否一致, 如果不一致, 就会抛出错误. 上面的断言的意思是指: 有.num这类名的节点的内容应该为数字1. 断言库库有很多种, Mocha并不限制你需要使用哪一种断言库, Vue的脚手架提供的断言库是sino-chai, 是一个基于Chai的断言库, 并且我们指定使用的是它的expect断言风格.
expect断言风格的优点很接近于自然语言, 下面是一些例子
// 相等或不相等expect(1+1).to.be.equal(2);expect(1+1).to.be.not.equal(3);// 布尔值为trueexpect('hello').to.be.ok;expect(false).to.not.be.ok;// typeofexpect('test').to.be.a('string');expect({foo:'bar'}).to.be.an('object');expect(foo).to.be.an.instanceof(Foo);// includeexpect([1,2,3]).to.include(2);expect('foobar').to.contain('foo');expect({foo:'bar',hello:'universe'}).to.include.keys('foo');// emptyexpect([]).to.be.empty;expect('').to.be.empty;expect({}).to.be.empty;// matchexpect('foobar').to.match(/^foo/);
每一个it()所包裹的测试用例都应该有一句或多句断言,上面只是介绍了一部分的断言语法, 如果想要知道更多Chai的断言语法, 请查看以下的官方文档.
Chai官方文档:http://chaijs.com/
Chai官方文档翻译:http://www.jianshu.com/p/f200a75a15d2
(三) Vue-test-utils测试库
1. 在测试脚本中引入vue-test-utils
//Counter.spec.jsimportVuefrom'vue'importCounterfrom'@/components/Counter'//引入vue-test-utilsimport{mount}from'vue-test-utils'
2. 测试文本内容
下面我将在Counter.spec.js测试脚本中对Counter.vue中
的文本内容进行测试, 大家可以直观的感受一下使用了Vue-test-utils后对.vue单文件组件的测试变得多么简单.
未使用vue-test-utils的测试用例:
it('未使用Vue-test-utils: 正确渲染h3的文字为Counter.vue',()=>{constConstructor=Vue.extend(Counter);constvm=newConstructor().$mount();constH3=vm.$el.querySelector('h3').textContent;expect(H3).to.equal('Counter.vue');})
使用了vue-test-utils的测试用例:
it('使用Vue-test-Utils: 正确渲染h3的文字为Counter.vue',()=>{constwrapper=mount(Counter);expect(wrapper.find('h3').text()).to.equal('Counter.vue');})
从上面的代码可以看出, vue-test-utils工具将该测试用例的代码量减少了一半, 如果是更复杂的测试用例, 那么代码量的减少将更为突出. 它可以让我们更专注于去写文件的测试逻辑, 将获取组件实例和挂载的繁琐的操作交由vue-test-utils去完成.
3. vue-test-utils的常用API
find(): 返回匹配选择器的第一个DOM节点或Vue组件的wrapper, 可以使用任何有效的选择器
text(): 返回wrapper的文本内容
html(): 返回wrapper DOM的HTML字符串
it('find()/text()/html()方法',()=>{constwrapper=mount(Counter);consth3=wrapper.find('h3');expect(h3.text()).to.equal('Counter.vue');expect(h3.html()).to.equal('
Counter.vue ');})
trigger(): 在该wrapper DOM节点上触发一个事件。
it('trigger()方法',()=>{constwrapper=mount(Counter);constbuttonOfSync=wrapper.find('.sync-button');buttonOfSync.trigger('click');buttonOfSync.trigger('click');constcount=Number(wrapper.find('.num').text());expect(count).to.equal(2);})
setData(): 设置data的属性并强制更新
it('setData()方法',()=>{constwrapper=mount(Counter);wrapper.setData({foo:'bar'});expect(wrapper.vm.foo).to.equal('bar');})
上面介绍了几个vue-test-utils提供的方法, 如果想深入学习vue-test-utils, 请阅读下面的官方文档:
vue-test-utils官方文档:https://vue-test-utils.vuejs.org/zh-cn/
三. 项目说明
该项目模仿了一个简单的微博, 在代码仓库下载后, 可直接通过npm run dev运行.
(一) 项目效果图
项目展示
(二) 项目中的交互逻辑和需求
在文本框中输入内容后点击"发布"按钮(1), 会新发布内容到微博列表中, 且个人头像等下的微博数量(6)会增加1个
当文本框中无内容时, 不能发布空微博到微博列表, 且弹出提示框, 叫用户输入内容
当点击"关注"(2), 个人头像下关注的数量(5)会增加1个, 且按钮内字体变成"取消关注"; 当点击"取消关注"(2), 个人头像下的数量(5)会减少1个, 且按钮内字体变成"关注"
当点击"收藏"(3)时, 我的收藏(7)会增加1个数量, 且按钮内文字变成"已收藏"; 点击"已收藏"(3)时, 我的收藏(7)会减少1个数量, 且按钮内文字变成"收藏"
当点击"赞"(4), 我的赞(8)会增加1个数量, 且按钮内文字变成"取消赞"; 点击"取消赞"(3)时, 我的赞(8)会减少1个数量, 且按钮内文字变成"赞"
(三) 项目源码
//SinaWeibo.vue{{content}} ({{collectNum}}) ({{likeNum}}) 发布 {{news.name}}{{news.resource}}关注取消关注{{news.content}}{{news.collect?"已收藏":'收藏'}} 转发 评论 {{news.like?'取消赞':'赞'}} Lee_tanghui{{profile.num}}{{profile.text}}Wish you like my blog!---LITANGHUI
四. 项目单元测试脚本实战
我们将以上文提到的"项目中的交互逻辑和需求"为基础, 为SinaWeibo.vue编写测试脚本, 下面我将展示测试用例编写过程:
1.在文本框中输入内容后点击"发布"按钮(1), 会新发布内容到微博列表中, 且个人头像等下的微博数量(6)会增加1个
it('点击发布按钮,发布新内容&个人微博数量增加1个',()=>{constwrapper=mount(SinaWeibo);consttextArea=wrapper.find('.weibo-publish-wrapper textarea');constbuttonOfPublish=wrapper.find('.weibo-publish-wrapper button');constlengthOfWeiboNews=wrapper.vm.weiboNews.length;constcountOfMyWeibo=wrapper.vm.profileData[2].num;//设置textArea的绑定数据wrapper.setData({newWeiboContent:{imgUrl:'../../static/image/profile.jpg',name:'Lee_tanghui',resource:'刚刚 来自 网页版微博',content:'欢迎来到我的微博',images:[]}});//触发点击事件buttonOfPublish.trigger('click');constlengthOfWeiboNewsAfterPublish=wrapper.vm.weiboNews.length;constcountOfMyWeiboAfterPublish=wrapper.vm.profileData[2].num;//断言: 发布新内容expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews+1);//断言: 个人微博数量增加1个expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo+1);})
测试结果:
通过测试
2.当文本框中无内容时, 不能发布空微博到微博列表, 且弹出提示框, 叫用户输入内容
it('当文本框中无内容时, 不能发布空微博到微博列表, 且弹出提示框',()=>{constwrapper=mount(SinaWeibo);consttextArea=wrapper.find('.weibo-publish-wrapper textarea');constbuttonOfPublish=wrapper.find('.weibo-publish-wrapper button');constlengthOfWeiboNews=wrapper.vm.weiboNews.length;constcountOfMyWeibo=wrapper.vm.profileData[2].num;//设置textArea的绑定数据为空wrapper.setData({newWeiboContent:{imgUrl:'../../static/image/profile.jpg',name:'Lee_tanghui',resource:'刚刚 来自 网页版微博',content:'',images:[]}});//触发点击事件buttonOfPublish.trigger('click');constlengthOfWeiboNewsAfterPublish=wrapper.vm.weiboNews.length;constcountOfMyWeiboAfterPublish=wrapper.vm.profileData[2].num;//断言: 没有发布新内容expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews);//断言: 个人微博数量不变expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo);})
测试结果:
image_1c2l52h0i11e51fjqm9o8751m7hm.png-32.4kB
3.当点击"关注"(2), 个人头像下关注的数量(5)会增加1个, 且按钮内字体变成"取消关注"; 当点击"取消关注"(2), 个人头像下的数量(5)会减少1个, 且按钮内字体变成"关注"
it('当点击"关注", 个人头像下关注的数量会增加1个, 且按钮内字体变成"取消关注"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfAddAttendion=wrapper.find('.add');constcountOfMyAttention=wrapper.vm.profileData[0].num;//触发事件buttonOfAddAttendion.trigger('click');constcountOfMyAttentionAfterClick=wrapper.vm.profileData[0].num;//断言: 个人头像下关注的数量会增加1个expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention+1);//断言: 按钮内字体变成"取消关注expect(buttonOfAddAttendion.text()).to.equal('取消关注');})
it('当点击"取消关注", 个人头像下关注的数量会减少1个, 且按钮内字体变成"关注"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfUnAttendion=wrapper.find('.cancel');constcountOfMyAttention=wrapper.vm.profileData[0].num;//触发事件buttonOfUnAttendion.trigger('click');constcountOfMyAttentionAfterClick=wrapper.vm.profileData[0].num;//断言: 个人头像下关注的数量会增加1个expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention-1);//断言: 按钮内字体变成"取消关注expect(buttonOfUnAttendion.text()).to.equal('关注');})
测试结果:
image_1c2lbcvod1d7ton71mod1i6b1bt13.png-62.3kB
4.当点击"收藏"(3)时, 我的收藏(7)会增加1个数量, 且按钮内文字变成"已收藏"; 点击"已收藏"(3)时, 我的收藏(7)会减少1个数量, 且按钮内文字变成"收藏"
it('当点击"收藏"时, 我的收藏会增加1个数量, 且按钮内文字变成"已收藏"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfCollect=wrapper.find('.collectWeibo');constcountOfMyCollect=Number(wrapper.find('.collect-num span').text());//触发点击事件buttonOfCollect.trigger('click');constcountOfMyCollectAfterClick=Number(wrapper.find('.collect-num span').text());//断言: 我的收藏数量会加1expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect+1);//断言: 按钮内文字变成已收藏expect(buttonOfCollect.text()).to.equal('已收藏');})
it('当点击"已收藏"时, 我的收藏会减少1个数量, 且按钮内文字变成"收藏"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfUnCollect=wrapper.find('.uncollectWeibo');constcountOfMyCollect=Number(wrapper.find('.collect-num span').text());//触发点击事件buttonOfUnCollect.trigger('click');constcountOfMyCollectAfterClick=Number(wrapper.find('.collect-num span').text());//断言: 我的收藏数量会减1expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect-1);//断言: 按钮内文字变成已收藏expect(buttonOfUnCollect.text()).to.equal('收藏');})
测试结果:
image_1c2lbdfe9i5jrja10cc447rgj1g.png-88.6kB
5.当点击"赞"(4), 我的赞(8)会增加1个数量, 且按钮内文字变成"取消赞"; 点击"取消赞"(3)时, 我的赞(8)会减少1个数量, 且按钮内文字变成"赞"
it('当点击"赞", 我的赞会增加1个数量, 且按钮内文字变成"取消赞"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfLike=wrapper.find('.dislikedWeibo');constcountOfMyLike=Number(wrapper.find('.like-num span').text());//触发点击事件buttonOfLike.trigger('click');constcountOfMyLikeAfterClick=Number(wrapper.find('.like-num span').text());//断言: 我的赞会增加1个数量expect(countOfMyLikeAfterClick).to.equal(countOfMyLike+1);//断言: 按钮内文字变成取消赞expect(buttonOfLike.text()).to.equal('取消赞');});
it('当点击"取消赞", 我的赞会减少1个数量, 且按钮内文字变成"赞"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfDislike=wrapper.find('.likedWeibo');constcountOfMyLike=Number(wrapper.find('.like-num span').text());//触发点击事件buttonOfDislike.trigger('click');constcountOfMyLikeAfterClick=Number(wrapper.find('.like-num span').text());//断言: 我的赞会增加1个数量expect(countOfMyLikeAfterClick).to.equal(countOfMyLike-1);//断言: 按钮内文字变成取消赞expect(buttonOfDislike.text()).to.equal('赞');});
测试结果
作者:李棠辉
链接:https://www.jianshu.com/p/38a37d5fccb2
来源:
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
你可能感兴趣的:(Vue单元测试实战教程(Mocha/Karma + Vue-Test-Utils + Chai))
vue中Axios的封装和API接口的管理(待根据实际项目front进行分析)
yinxiangzhongqing
vue.js 前端 javascript
axios的封装和api接口的统一管理,其实主要目的就是在帮助我们简化代码和利于后期的更新维护。一、axios的封装在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御XSRF等。所以我们的尤大大也是果断放弃了对其官方库vue-reso
(一)React 基础
小刀肉0812
React react.js 前端 前端框架
专栏持续更新中~~目录目录一、React介绍1.1什么是React1.2React的特点1.3ReactVSVueVSAngular1.基本概述2.语法和核心概念对比2.1组件语法2.1.1React组件2.1.2Vue组件2.1.3Angular组件2.2数据绑定2.2.1React(单向数据流)2.2.2Vue(双向数据绑定)2.2.3Angular(双向数据绑定)2.3事件绑定3.性能对比4
敏捷开发之自动化流水线
舒旻
敏捷项目管理 devops 敏捷流程 scrum 软件工程 敏捷开发
自动化流水线就像给软件交付装上了「智能检测仪」,每个环节自动过滤风险,确保最终交付物既安全又高质量。以下是一个在线教育平台支付系统升级的实战案例,完整展示从开发到上线的全流程。以下是「在线教育平台支付系统升级」案例的完整责任矩阵:责任分工框架环节主要责任人协作角色关键交付物协作工具1.代码开发与提交后端开发工程师技术负责人、产品经理功能代码、单元测试GitLab、JIRA2.代码安全审查安全工程师
Codeforces Beta Round 4 (Div. 2 Only) 4D. Mysterious Present (最长上升子序列变形)
H_z___
算法
题目:PeterdecidedtowishhappybirthdaytohisfriendfromAustraliaandsendhimacard.Tomakehispresentmoremysterious,hedecidedtomakeachain.ChainhereissuchasequenceofenvelopesA = {a1, a2, ..., an},wherethewidth
Vue打印组件
_AndyLau
vue.js
Vue打印组件vue-print-nb是一个用于Vue.js的轻量级打印插件,它允许你轻松地将页面或特定元素转换为可打印格式,并提供了额外的功能如预览和生成PDF。下面是使用vue-print-nb的步骤:安装首先,你需要通过npm或yarn来安装vue-print-nb。bash深色版本npminstallvue-print-nb--save#或者yarnaddvue-print-nb引入并注册
构建一个支持精度、范围和负数的-Vue-数字输入框
xChive
Vue 前端 vue.js 前端 javascript 自定义组件
分析并实现一个支持精度、范围和负数控制的数字输入框。背景在很多业务中,我们经常需要使用数字输入框,通常这些输入框会涉及到数字校验,比如限制输入范围、设置小数精度、是否允许负数等。每次写表单时,都需要重复定义这些校验规则,这不仅繁琐,而且无法满足灵活配置的需求。因此,我想到了能否将这些功能抽象成一个通用的、可复用的组件,避免每次都写重复的逻辑。思路直接限制输入,处理好输入的内容,就可以避免复杂的校验
Java版工程行业管理系统源码-专业的工程管理软件- 工程项目各模块及其功能点清单
m0_72864708
java 企业工程管理系统源码 工程管理系统 工程行业管理系统源码
工程项目管理系统的技术革新与数字化转型随着科技的飞速发展,工程项目管理领域正经历着前所未有的变革。在这个变革中,一款先进的工程项目管理软件应运而生,它不仅提升了项目管理的效率和质量,更推动了企业数字化转型的进程。这款工程项目管理软件采用了Vue、Uniapp、Layui等前沿技术框架,构建了一个覆盖项目全生命周期的综合管理平台。从项目策划决策、规划设计,到施工建设、竣工交付,再到总结评估和运维运营
使用 vxe-table 实现复选框分页跨页勾选
vue.js
vxe-table实现复选框分页跨页勾选官网:https://vxetable.cn当使用数据分页与复选框多页勾选时,可以通过checkbox-config.reserve启用获取已选import{ref,reactive}from'vue'import{VxeUI}from'vxe-table'constgridRef=ref()constallList=[{id:10001,name:'Tes
vue vxe-table 实现财务记账凭证
vue.js
使用vxe-table实现财务记账凭证非常简单,实现在线实时编辑的记账凭证、自动合计金额等官网:https://vxetable.cn/新增保存财务主管:小徐记账:张三出纳:李四审核:老六import{ref,reactive,nextTick}from'vue'import{VxeUI}from'vxe-table'importXEUtilsfrom'xe-utils'constgridRef=
vxe-table v4.8+ 实现行拖动排序,列拖动排序
vue.js
VxeUIvuevxe-tablev4.8+实现行拖动排序,列拖动排序安装
[email protected] @4.8.1main.js//...importVxeUIfrom'vxe-pc-ui'import'vxe-pc-ui/lib/style.css'importVxeUITablefrom'vxe-table'import'vxe-table/lib/s
软件工程---软件测试
Dragonlongbo
软件工程
软件测试是指在软件开发过程中,通过一系列的测试活动来评估和验证软件系统或应用程序的质量。它是一种用于发现和修复软件缺陷、错误和问题的过程,旨在确保软件能够满足其预期功能、性能和安全需求。软件测试分类软件测试可以按照多个维度进行分类,最常见的分类方式有以下几种:按测试阶段分:单元测试、集成测试、系统测试、验收测试按测试目的分:功能测试、性能测试、安全测试、兼容性测试按测试覆盖范围分:回归测试、全面测
基于Spring Boot+vue的厨艺交流平台系统设计与实现
程序媛小果
毕设 java精品毕设 前端 spring boot vue.js 后端
大家好,今天要和大家聊的是一款基于SpringBoot的“厨艺交流平台”系统的设计与实现。项目源码以及部署相关事宜请联系我,文末附上联系方式。项目简介基于SpringBoot的“厨艺交流平台”系统设计与实现的主要使用者分为管理员、普通用户和游客。没有授权的用户无法使用本系统功能,包括个人中心、食材分类管理、用户管理、菜品分类管理、菜谱信息管理、食材信息管理、商品分类管理、商品信息管理、美食日志管理
VUE + Jquery 集成的一个简易数学公式编辑器
今天也想MK代码
努力把想法实现 vue jquery js web html
前端数学公式自定义编辑界面可自定义未知数、运算符号、函数自己写的一个数学公式简单编辑器,本想找开源,无奈找不到。如果有开源,请发我一份,参考参考。在此感谢。静态1、简单公式:例如x+y将公式中的变量(x,y)以及运算符(+,-)放在一个数组中,遍历这个这个数组组成一个html字符串,然后显示在页面。数组定义为:type定义是值还是运算符valueDatas:[{type:'value',domTy
vue项目同时使用sass和less
shalDream
vue npm javascript less
有时因为代码需要,需要同时使用sass和less,现将本人的一点经验心得分享给大家。1.首先建议安装淘宝镜像,如已安装可跳过命令:npminstall-gcnpm--registry=https://registry.npm.taobao.org2.如项目中已有sass,需要安装less,执行如下代码:
[email protected] .
vue3+vite+ts项目中使用vue-router
枫叶&情缘
Vue vue.js 前端 javascript
vite.config.ts:import{defineConfig}from'vite';importvuefrom'@vitejs/plugin-vue';importpathfrom"path";exportdefaultdefineConfig({plugins:[vue()],resolve:{alias:{"@":path.resolve(__dirname,"src"),}},});
vue2中使用Animate.css动画插件
T-shmily
前端 vue.js 动画
①安装Animate官网npminstallanimate.css--saveyarnaddanimate.css或者直接下载②引入在main.js中importanimatedfrom"animate.css";Vue.use(animated)或import'animate.css';也可以直接引入在需要用动画的组件中import'animate.css'③使用vue官网vue官网Transi
【AI大模型应用开发】【LangChain系列】5. 实战LangChain的智能体Agents模块
同学小张
大模型 人工智能 langchain python 笔记 agi gpt AI-native
大家好,我是【同学小张】。持续学习,持续干货输出,关注我,跟我一起学AI大模型技能。在我前面的MetaGPT系列文章中,已经对智能体有了一个认知,重温一下:智能体=LLM+观察+思考+行动+记忆将大语言模型作为一个推理引擎。给定一个任务,智能体自动生成完成任务所需的步骤,执行相应动作(例如选择并调用工具),直到任务完成。更详细的智能体相关概念可看我前面的文章:【AI的未来-AIAgent系列】【M
基于vue3封装axios
withNanSi
笔记总结 vue javascript
安装axiosyarnaddaxios实例化axios–设置baseURL,超时时间,大数问题constinstance=axios.create({baseURL:'',timeout:5000})请求拦截器-全局注入tokeninstance.interceptors.request.use(config=>{//config是请求//1.获取token,从user模块中获取
影院购票系统(二)——uni-app移动应用开发
阿常11
uni-app移动应用开发 uni-app javascript 开发语言
这一篇讲解系统的逻辑代码部分,下面是ai的讲解,也可以直接跳到代码部分进行浏览。一、整体功能概述这个Vue组件构建了一个完整的影院座位选择系统,涵盖从座位数据初始化、视图渲染到交互处理以及业务逻辑的整个流程。它遵循响应式编程模式,数据的变化能够及时反映在视图上,反之亦然。二、核心数据结构剖析seatData二维数组组件利用Vue的响应式数据模型,定义了seatData这个二维数组,用来表示9x14
学Rust写CAD】9 变量类
Source.Liu
学Rust写CAD rust
Variable结构体,封装了一个泛型值T,其中T必须满足FloatTypetrait的约束。FloatTypetrait确保T实现了必要的算术操作(Mul、Add、Neg)以及Copytrait。还为Variable实现了各种算术操作,并提供了单元测试来验证这些操作的正确性。一、代码/**变量结构体Variable*该结构体泛型参数T需满足FloatType约束*/usestd::ops::{M
【智能体Agent】ReAct智能体的实现思路和关键技术
星星点点洲
LangChain开发过程 langchain
基于ReAct(Reasoning+Acting)框架的自主智能体importrefromtypingimportList,Tuplefromlangchain_community.chat_message_histories.in_memoryimportChatMessageHistoryfromlangchain_core.language_models.chat_modelsimportB
升级《在线写python》小程序的分享功能。昨天忘了...
陈钇谷
python 小程序 notepad++
小程序是使用uniapp写的,忘了开启分享功能,导致它现在是这样的。挺不方便的,所以需要开启分享权限,由于我这个没有其他需要隐藏的私密页面,所以事直接全局开启就行在App.vue文件里的onShow里开启即可。加入如下代码:uni.getSystemInfo({success:res=>{if(res.uniPlatform==='mp-weixin'){uni.showShareMenu({wi
园区环境数字化管理系统(源码+文档+讲解+演示)
开源项目介绍
引言随着工业化和城市化的快速发展,园区环境管理面临着越来越多的挑战。园区环境数字化管理系统通过数字化手段,为园区管理者提供了一个高效、透明、智能的管理平台。本文将详细介绍园区环境数字化管理系统的功能、技术架构以及其在提升园区环境管理效率中的优势。系统概述园区环境数字化管理系统采用前后端分离的架构设计,服务端基于MySQL5.7+、JDK1.8+和Redis,前端则采用Vue2.6.14和Eleme
生命周期总结(uni-app、vue2、vue3生命周期讲解)
露西西★
前端 javascript 前端 前端框架
一、vue2生命周期Vue2的生命周期钩子函数分为4个阶段:创建、挂载、更新、销毁。1.创建阶段beforeCreate:实例初始化之后,数据观测和事件配置之前。created:实例创建完成,数据观测和事件配置已完成,但DOM未生成。2.挂载阶段beforeMount:模板编译完成,但未挂载到DOM。mounted:实例挂载到DOM后调用,DOM已生成。3.更新阶段beforeUpdate:数据更
基于 uni-app 和 Vue3 开发的汉字书写练习应用
xiyueta
uni-app canvas
基于uni-app和Vue3开发的汉字书写练习应用前言本文介绍了如何使用uni-app+Vue3+uview-plus开发一个汉字书写练习应用。该应用支持笔画演示、书写练习、进度保存等功能,可以帮助用户学习汉字书写。在线演示演示地址:http://demo.xiyueta.com/case/web20250222/#/pagesa/xiehaizi/index测试账号:demo测试密码:12345
axios在vue3中的封装处理
每天都在努力学习的刘同学
js ajax
Axios封装处理本节目标:基于axios封装一个请求模块,调用接口时使用1)安装axiosnpmiaxios2)新建src/utils/request.js模块//封装全局request请求的方法importaxiosfrom'axios'//vueximportstorefrom'@/store'//导入路由实例importrouterfrom'@/router'//baseURL超时时间配置
wangeditor html编辑,Vue整合wangEditor富文本编辑器
莫姐
wangeditor html编辑
最近在做项目时,客户有个发布新闻动态的功能,具体页面内容让客户自己编写,所以要选择富文本编辑器,这样用户体验好一点。网上有很多的富文本编辑器,因为项目的功能并不是很复杂,所以选择了wangEditor,界面简洁,使用起来也挺方便的;image.png实现思路1.安装wangEditor2.封装成组件3.父组件中直接调用一、wangEditor安装这里使用npm命令安装;npminstallwang
vue表单已经赋值了,但是还是返回async-validator “xxx is required“提示,弹出验证红字而且不能输入
野猪佩奇007
vue.js javascript 前端
1.验证规则的定义问题首先检查一下你的验证规则是否正确。Vue表单验证通常是用rules来设置的。如果字段值已经赋值,但仍然提示必填项错误,可能是规则写得有问题。你可以确保xxx字段的验证规则中required设置是正确的。先确认字段值有没有初始化,也就是form里该字段有没有写上,先初始化例如:rules:{xxx:[{required:true,message:'联系人不能为空',trigge
Composition API
大麦大麦
2025 前端面经 android es6 前端 面试 javascript 开发语言
为什么会产生CompositionAPI?Vue2逻辑复用方式缺点Mixin(命名空间冲突、逻辑不清晰、不易复用)scopedslot作用域插槽(配置项多、代码分裂、性能差)Vue2对TS支持不充分CompositionAPI优点逻辑代码更少,更集中,更易扩展更加丰富的API集成对TS来说,非常友好(利于类型推导)Vue2与Vue3编写风格上的区别data的变量定义与methods的方法定义->整
Vue 3 实现富文本内容导出 Word 文档:前端直出方案与优化实践
茶颜悅色
前端 vue.js word
本文将深入讲解如何通过纯前端方案将富文本内容直接导出为符合中文排版规范的Word文档,对比传统服务端生成方案,本方案可降低服务器压力80%以上,同时支持即时下载功能。一、功能全景图该方案实现以下核心能力:✅纯前端Word文档生成✅中文仿宋字体完美支持✅智能分页与页边距控制✅内存安全回收机制✅浏览器全兼容方案二、技术方案对比方案响应速度服务器压力兼容性要求实现复杂度服务端生成(传统方案)慢高低高前端
微信开发者验证接口开发
362217990
微信 开发者 token 验证
微信开发者接口验证。
Token,自己随便定义,与微信填写一致就可以了。
根据微信接入指南描述 http://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html
第一步:填写服务器配置
第二步:验证服务器地址的有效性
第三步:依据接口文档实现业务逻辑
这里主要讲第二步验证服务器有效性。
建一个
一个小编程题-类似约瑟夫环问题
BrokenDreams
编程
今天群友出了一题:
一个数列,把第一个元素删除,然后把第二个元素放到数列的最后,依次操作下去,直到把数列中所有的数都删除,要求依次打印出这个过程中删除的数。
&
linux复习笔记之bash shell (5) 关于减号-的作用
eksliang
linux关于减号“-”的含义 linux关于减号“-”的用途 linux关于“-”的含义 linux关于减号的含义
转载请出自出处:
http://eksliang.iteye.com/blog/2105677
管道命令在bash的连续处理程序中是相当重要的,尤其在使用到前一个命令的studout(标准输出)作为这次的stdin(标准输入)时,就显得太重要了,某些命令需要用到文件名,例如上篇文档的的切割命令(split)、还有
Unix(3)
18289753290
unix ksh
1)若该变量需要在其他子进程执行,则可用"$变量名称"或${变量}累加内容
什么是子进程?在我目前这个shell情况下,去打开一个新的shell,新的那个shell就是子进程。一般状态下,父进程的自定义变量是无法在子进程内使用的,但通过export将变量变成环境变量后就能够在子进程里面应用了。
2)条件判断: &&代表and ||代表or&nbs
关于ListView中性能优化中图片加载问题
酷的飞上天空
ListView
ListView的性能优化网上很多信息,但是涉及到异步加载图片问题就会出现问题。
具体参看上篇文章http://314858770.iteye.com/admin/blogs/1217594
如果每次都重新inflate一个新的View出来肯定会造成性能损失严重,可能会出现listview滚动是很卡的情况,还会出现内存溢出。
现在想出一个方法就是每次都添加一个标识,然后设置图
德国总理默多克:给国人的一堂“震撼教育”课
永夜-极光
教育
http://bbs.voc.com.cn/topic-2443617-1-1.html德国总理默多克:给国人的一堂“震撼教育”课
安吉拉—默克尔,一位经历过社会主义的东德人,她利用自己的博客,发表一番来华前的谈话,该说的话,都在上面说了,全世界想看想传播——去看看默克尔总理的博客吧!
德国总理默克尔以她的低调、朴素、谦和、平易近人等品格给国人留下了深刻印象。她以实际行动为中国人上了一堂
关于Java继承的一个小问题。。。
随便小屋
java
今天看Java 编程思想的时候遇见一个问题,运行的结果和自己想想的完全不一样。先把代码贴出来!
//CanFight接口
interface Canfight {
void fight();
}
//ActionCharacter类
class ActionCharacter {
public void fight() {
System.out.pr
23种基本的设计模式
aijuans
设计模式
Abstract Factory:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 Adapter:将一个类的接口转换成客户希望的另外一个接口。A d a p t e r模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 Bridge:将抽象部分与它的实现部分分离,使它们都可以独立地变化。 Builder:将一个复杂对象的构建与它的表示分离,使得同
《周鸿祎自述:我的互联网方法论》读书笔记
aoyouzi
读书笔记
从用户的角度来看,能解决问题的产品才是好产品,能方便/快速地解决问题的产品,就是一流产品.
商业模式不是赚钱模式
一款产品免费获得海量用户后,它的边际成本趋于0,然后再通过广告或者增值服务的方式赚钱,实际上就是创造了新的价值链.
商业模式的基础是用户,木有用户,任何商业模式都是浮云.商业模式的核心是产品,本质是通过产品为用户创造价值.
商业模式还包括寻找需求
JavaScript动态改变样式访问技术
百合不是茶
JavaScript style属性 ClassName属性
一:style属性
格式:
HTML元素.style.样式属性="值";
创建菜单:在html标签中创建 或者 在head标签中用数组创建
<html>
<head>
<title>style改变样式</title>
</head>
&l
jQuery的deferred对象详解
bijian1013
jquery deferred对象
jQuery的开发速度很快,几乎每半年一个大版本,每两个月一个小版本。
每个版本都会引入一些新功能,从jQuery 1.5.0版本开始引入的一个新功能----deferred对象。
&nb
淘宝开放平台TOP
Bill_chen
C++ c 物流 C#
淘宝网开放平台首页:http://open.taobao.com/
淘宝开放平台是淘宝TOP团队的产品,TOP即TaoBao Open Platform,
是淘宝合作伙伴开发、发布、交易其服务的平台。
支撑TOP的三条主线为:
1.开放数据和业务流程
* 以API数据形式开放商品、交易、物流等业务;
&
【大型网站架构一】大型网站架构概述
bit1129
网站架构
大型互联网特点
面对海量用户、海量数据
大型互联网架构的关键指标
高并发
高性能
高可用
高可扩展性
线性伸缩性
安全性
大型互联网技术要点
前端优化
CDN缓存
反向代理
KV缓存
消息系统
分布式存储
NoSQL数据库
搜索
监控
安全
想到的问题:
1.对于订单系统这种事务型系统,如
eclipse插件hibernate tools安装
白糖_
Hibernate
eclipse helios(3.6)版
1.启动eclipse 2.选择 Help > Install New Software...> 3.添加如下地址:
http://download.jboss.org/jbosstools/updates/stable/helios/ 4.选择性安装:hibernate tools在All Jboss tool
Jquery easyui Form表单提交注意事项
bozch
jquery easyui
jquery easyui对表单的提交进行了封装,提交的方式采用的是ajax的方式,在开发的时候应该注意的事项如下:
1、在定义form标签的时候,要将method属性设置成post或者get,特别是进行大字段的文本信息提交的时候,要将method设置成post方式提交,否则页面会抛出跨域访问等异常。所以这个要
Trie tree(字典树)的Java实现及其应用-统计以某字符串为前缀的单词的数量
bylijinnan
java实现
import java.util.LinkedList;
public class CaseInsensitiveTrie {
/**
字典树的Java实现。实现了插入、查询以及深度优先遍历。
Trie tree's java implementation.(Insert,Search,DFS)
Problem Description
Igna
html css 鼠标形状样式汇总
chenbowen00
html css
css鼠标手型cursor中hand与pointer
Example:CSS鼠标手型效果 <a href="#" style="cursor:hand">CSS鼠标手型效果</a><br/>
Example:CSS鼠标手型效果 <a href="#" style=&qu
[IT与投资]IT投资的几个原则
comsci
it
无论是想在电商,软件,硬件还是互联网领域投资,都需要大量资金,虽然各个国家政府在媒体上都给予大家承诺,既要让市场的流动性宽松,又要保持经济的高速增长....但是,事实上,整个市场和社会对于真正的资金投入是非常渴望的,也就是说,表面上看起来,市场很活跃,但是投入的资金并不是很充足的......
oracle with语句详解
daizj
oracle with with as
oracle with语句详解 转
在oracle中,select 查询语句,可以使用with,就是一个子查询,oracle 会把子查询的结果放到临时表中,可以反复使用
例子:注意,这是sql语句,不是pl/sql语句, 可以直接放到jdbc执行的
----------------------------------------------------------------
hbase的简单操作
deng520159
数据库 hbase
近期公司用hbase来存储日志,然后再来分析 ,把hbase开发经常要用的命令找了出来.
用ssh登陆安装hbase那台linux后
用hbase shell进行hbase命令控制台!
表的管理
1)查看有哪些表
hbase(main)> list
2)创建表
# 语法:create <table>, {NAME => <family&g
C语言scanf继续学习、算术运算符学习和逻辑运算符
dcj3sjt126com
c
/*
2013年3月11日20:37:32
地点:北京潘家园
功能:完成用户格式化输入多个值
目的:学习scanf函数的使用
*/
# include <stdio.h>
int main(void)
{
int i, j, k;
printf("please input three number:\n"); //提示用
2015越来越好
dcj3sjt126com
歌曲
越来越好
房子大了电话小了 感觉越来越好
假期多了收入高了 工作越来越好
商品精了价格活了 心情越来越好
天更蓝了水更清了 环境越来越好
活得有奔头人会步步高
想做到你要努力去做到
幸福的笑容天天挂眉梢 越来越好
婆媳和了家庭暖了 生活越来越好
孩子高了懂事多了 学习越来越好
朋友多了心相通了 大家越来越好
道路宽了心气顺了 日子越来越好
活的有精神人就不显
java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Tim
feiteyizu
mysql
数据表中有记录的time字段(属性为timestamp)其值为:“0000-00-00 00:00:00”
程序使用select 语句从中取数据时出现以下异常:
java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date
java.sql.SQLException: Valu
Ehcache(07)——Ehcache对并发的支持
234390216
并发 ehcache 锁 ReadLock WriteLock
Ehcache对并发的支持
在高并发的情况下,使用Ehcache缓存时,由于并发的读与写,我们读的数据有可能是错误的,我们写的数据也有可能意外的被覆盖。所幸的是Ehcache为我们提供了针对于缓存元素Key的Read(读)、Write(写)锁。当一个线程获取了某一Key的Read锁之后,其它线程获取针对于同
mysql中blob,text字段的合成索引
jackyrong
mysql
在mysql中,原来有一个叫合成索引的,可以提高blob,text字段的效率性能,
但只能用在精确查询,核心是增加一个列,然后可以用md5进行散列,用散列值查找
则速度快
比如:
create table abc(id varchar(10),context blog,hash_value varchar(40));
insert into abc(1,rep
逻辑运算与移位运算
latty
位运算 逻辑运算
源码:正数的补码与原码相同例+7 源码:00000111 补码 :00000111 (用8位二进制表示一个数)
负数的补码:
符号位为1,其余位为该数绝对值的原码按位取反;然后整个数加1。 -7 源码: 10000111 ,其绝对值为00000111 取反加一:11111001 为-7补码
已知一个数的补码,求原码的操作分两种情况:
利用XSD 验证XML文件
newerdragon
java xml xsd
XSD文件 (XML Schema 语言也称作 XML Schema 定义(XML Schema Definition,XSD)。 具体使用方法和定义请参看:
http://www.w3school.com.cn/schema/index.asp
java自jdk1.5以上新增了SchemaFactory类 可以实现对XSD验证的支持,使用起来也很方便。
以下代码可用在J
搭建 CentOS 6 服务器(12) - Samba
rensanning
centos
(1)安装
# yum -y install samba
Installed:
samba.i686 0:3.6.9-169.el6_5
# pdbedit -a rensn
new password:123456
retype new password:123456
……
(2)Home文件夹
# mkdir /etc
Learn Nodejs 01
toknowme
nodejs
(1)下载nodejs
https://nodejs.org/download/ 选择相应的版本进行下载 (2)安装nodejs 安装的方式比较多,请baidu下
我这边下载的是“node-v0.12.7-linux-x64.tar.gz”这个版本 (1)上传服务器 (2)解压 tar -zxvf node-v0.12.
jquery控制自动刷新的代码举例
xp9802
jquery
1、html内容部分 复制代码代码示例: <div id='log_reload'>
<select name="id_s" size="1">
<option value='2'>-2s-</option>
<option value='3'>-3s-</option