一、问题背景
初次写单元测试,对于复杂的测试样例不知道怎么写,而且更重要的是,不确定自己写的断言是否合理。
请教:下面几个我想实现的测试用例,应该如何写,并且,这几个断言是合理的吗?不合理的话,应该怎么做呢?
二、代码
Manage.vue
<template lang="pug">
div
s-tabs.mins.mb-5(@tab-change="tabChange" ref="testtab")
s-tabs-nav
s-tab(href="tab-word") 敏感词管理
s-tab(href="tab-categoryReson") 类型原因管理
s-tabs-content
s-tabs-item(id="tab-word")
s-row.mb-2
s-col(xs12
sm8
lg6
xl4
v-for="(item, index) in categoryListWithoutData")
s-checkbox(
:label="item.name"
v-model="categoryListWithoutData[index].isCheck"
@change="categoryListChange")
s-row.mb-4
s-checkbox(
v-model="isCheckeAll"
label="全选"
@change="allCheckChange")
s-row.mb-4.justify-space-bwtween
s-search-box(:search="searchWord")
template(slot="base")
s-search-column
s-input(v-model="wordSearchParams.wordName"
placeholder="输入敏感词进行搜索"
width="300px")
router-link.right.ml-10(:to="'/sensitive-word/createWord'" target="_blank")
s-btn 新增
s-table.highlight(:data="wordList"
max-height="840"
border)
template(slot="empty")
Loading(v-if="isLoading")
span(v-else) 暂无数据
s-table-column(label="词类型")
template(slot-scope="scope")
span {{scope.row && scope.row.category_name}}
s-table-column(label="原因" min-width="120px")
template(slot-scope="scope")
span {{scope.row.reason}}
s-table-column(label="词汇" min-width="220px")
template(slot-scope="scope")
span(v-for="(item, index) in scope.row.word_list"
:class="{'text-error': wordSearchParams.wordName != '' && item.word == wordSearchParams.wordName}") {{ item.word }}
i(v-if="index < scope.row.word_list.length - 1") ,
s-table-column(label="操作" min-width="80")
template(slot-scope="scope")
router-link.underline(
target="_blank"
:to="{name: 'editWord', query: { 'category_id': scope.row.category_id, 'reason_id': scope.row.reason_id }}") 编辑
//- a.underline(href="javascript:void(0);" @click="gotoEdit") 编辑
Pagination(v-if="wordPageInfo.total" :page="wordPageInfo" :change="changeWordPage")
s-tabs-item(id="tab-categoryReson")
s-tabs(min)
s-tabs-nav
s-tab(href="tab-category") 词类型
s-tab(href="tab-reason") 违禁原因
s-tabs-content
s-tabs-item(id="tab-category")
s-row.justify-space-bwtween
s-search-box(:search="searchCategory")
template(slot="base")
s-search-column
s-input(v-model="categorySearchParams.categoryName"
placeholder="输入词类型进行搜索"
width="300px")
s-btn(@click.native="createCategory") 新增
s-table.highlight(:data="categoryListWithData"
border)
template(slot="empty")
Loading(v-if="isLoading")
span(v-else) 暂无数据
s-table-column(label="序号")
template(slot-scope="scope")
span {{scope.$index + 1}}
s-table-column(label="创建时间" min-width="100px")
template(slot-scope="scope")
span {{scope.row.created_time}}
s-table-column(label="词类型" min-width="180px")
template(slot-scope="scope")
span {{scope.row.name}}
s-table-column(label="词汇数量" min-width="180px")
template(slot-scope="scope")
span {{scope.row.word_count}}
s-table-column(label="操作")
template(slot-scope="scope")
a.mr-4.underline(href="javascript:void(0)" @click="editCategory(scope.row)") 编辑
a.underline(href="javascript:void(0)" @click="deleteCategory(scope.row)") 删除
Pagination(v-if="categoryPageInfo.total" :page="categoryPageInfo" :change="changeCategoryPage")
s-tabs-item(id="tab-reason")
s-row.justify-space-bwtween
s-search-box(:search="searchReason")
template(slot="base")
s-search-column
s-input(v-model="reasonSearchParams.reason"
placeholder="输入违禁原因进行搜索"
width="300px")
s-btn(@click.native="createReason") 新增
s-table.highlight(:data="reasonListWithData"
border)
template(slot="empty")
Loading(v-if="isLoading")
span(v-else) 暂无数据
s-table-column(label="序号")
template(slot-scope="scope")
span {{ (reasonPageInfo.per_page ) * (reasonPageInfo.current_page - 1) + scope.$index + 1 }}
s-table-column(label="创建时间" min-width="100px")
template(slot-scope="scope")
span {{scope.row.created_time}}
s-table-column(label="违禁原因" min-width="180px")
template(slot-scope="scope")
span {{scope.row.reason}}
s-table-column(label="词汇数量" min-width="180px")
template(slot-scope="scope")
span {{scope.row.word_count}}
s-table-column(label="操作")
template(slot-scope="scope")
a.mr-4.underline(href="javascript:void(0)" @click="editReason(scope.row)") 编辑
a.underline(href="javascript:void(0)" @click="deleteReason(scope.row)") 删除
Pagination(v-if="reasonPageInfo.total" :page="reasonPageInfo" :change="changeReasonPage")
</template>
<script>
import loading from '@/mixins/loading'
import pagination from '@/mixins/pagination'
import sensitiveWordApi from '@/api/sensitiveWord'
import CreateWord from '@/views/common/sensitiveWord/CreateWord';
import CreateCategory from '@/views/common/sensitiveWord/CreateCategory';
import CreateReason from '@/views/common/sensitiveWord/CreateReason';
import EditCategory from '@/views/common/sensitiveWord/EditCategory';
import EditReason from '@/views/common/sensitiveWord/EditReason';
import DeleteCategory from '@/views/common/sensitiveWord/DeleteCategory';
import DeleteReason from '@/views/common/sensitiveWord/DeleteReason';
import { trimObject } from '@/util';
export default {
name: 'sensitiveWord',
mixins: [loading, pagination],
data() {
return {
isCheckeAll: false,
channelList: [],
wordList: [],
categoryListWithoutData: [],
categoryListWithData: [],
categoryPageInfo: {
current_page: 1
},
categorySearchParams: {
categoryName: ''
},
reasonListWithData: [],
reasonPageInfo: {
current_page: 1
},
reasonSearchParams: {
reason: ''
},
isLoading: true,
curTab: 'tab-detail',
wordPageInfo: {
current_page: 1
},
wordSearchParams: {
wordName: ''
}
}
},
mounted() {
sensitiveWordApi.getCategoryListWithoutData()
.then((data)=> {
// let categoryIdList = [];
this.categoryListWithoutData = data;
// 默认不用勾选全部词类型
// for(let i = 0; i < this.categoryListWithoutData.length; i++) {
// this.categoryListWithoutData[i].isCheck = false;
// }
Promise.all([
sensitiveWordApi.getWordList(),
sensitiveWordApi.getCategoryListWithData({is_paging: 1}),
sensitiveWordApi.getReasonListWithData({is_paging: 1}),
]).then((datas)=> {
this.wordList = datas[0].items;
this.wordPageInfo = {
current_page: datas[0].page_info.page,
total: datas[0].page_info.total,
per_page: datas[0].page_info.page_size
};
this.categoryListWithData = datas[1].category_list;
this.categoryPageInfo = {
current_page: datas[1].page_info.page,
total: datas[1].page_info.total,
per_page: datas[1].page_info.page_size
};
this.reasonListWithData = datas[2].reason_list;
this.reasonPageInfo = {
current_page: datas[2].page_info.page,
total: datas[2].page_info.total,
per_page: datas[2].page_info.page_size
};
this.isLoading = false;
})
})
},
methods: {
allCheckChange() {
if(this.isCheckeAll) {
this.checkAllCategory()
} else {
this.notCheckAllCategory()
}
this.searchWord();
},
createWord() {
this.$starfish.dialog.open({
component: CreateWord,
props: {}
});
},
createCategory() {
this.$starfish.dialog.open({
component: CreateCategory,
props: {
reloadFun: this.searchCategory
}
});
},
createReason() {
this.$starfish.dialog.open({
component: CreateReason,
props: {
reloadFun: this.searchReason
}
});
},
editCategory(item) {
this.$starfish.dialog.open({
component: EditCategory,
props: {
data: {
category: item
},
reloadFun: this.searchCategory
}
});
},
editReason(item) {
this.$starfish.dialog.open({
component: EditReason,
props: {
data: {
reason: item
},
reloadFun: this.searchReason
}
});
},
deleteCategory(item) {
this.$starfish.dialog.open({
component: DeleteCategory,
props: {
data: {
category: item
},
reloadFun: this.searchCategory
}
});
},
deleteReason(item) {
this.$starfish.dialog.open({
component: DeleteReason,
props: {
data: {
reason: item
},
reloadFun: this.searchReason
}
});
},
/* getCategoryListWithData() {
this.isLoading = true;
sensitiveWordApi.getCategoryListWithData().then((data)=> {
this.categoryListWithData = data.category_list;
this.categoryPageInfo = {
current_page: data.page_info.page,
total: data.page_info.total,
per_page: data.page_info.page_size
};
this.isLoading = true;
});
}, */
/* getReasonListWithData() {
this.isLoading = true;
sensitiveWordApi.getReasonListWithData().then((data)=> {
this.reasonListWithData = data.reason_list;
this.reasonPageInfo = {
current_page: data.page_info.page,
total: data.page_info.total,
per_page: data.page_info.page_size
};
this.isLoading = true;
});
}, */
tabChange(tab) {
this.curTab = tab;
},
categoryListChange() {
this.wordPageInfo.current_page = 1;
// 更新全选按钮状态
if(this.getCategoryIdList().length == this.categoryListWithoutData.length) {
this.isCheckeAll = true;
} else {
this.isCheckeAll = false;
}
this.searchWord();
},
searchWord() {
this.isLoading = true;
let params = {
category_id_list: this.getCategoryIdList().length > 0? JSON.stringify(this.getCategoryIdList()): '',
word_name: this.wordSearchParams.wordName,
page: this.wordPageInfo.current_page,
limit: this.wordPageInfo.per_page
}
sensitiveWordApi.getWordList(trimObject(params)).then((data)=> {
this.wordList = data.items;
this.wordPageInfo = {
current_page: data.page_info.page,
total: data.page_info.total,
per_page: data.page_info.page_size
};
this.isLoading = false;
})
},
searchCategory() {
this.isLoading = true;
let params = {
category_name: this.categorySearchParams.categoryName,
is_paging: 1,
page: this.categoryPageInfo.current_page
}
sensitiveWordApi.getCategoryListWithData(trimObject(params)).then((data)=> {
this.categoryListWithData = data.category_list;
this.categoryPageInfo = {
current_page: data.page_info.page,
total: data.page_info.total,
per_page: data.page_info.page_size
};
this.isLoading = false;
})
},
searchReason() {
this.isLoading = true;
let params = {
reason: this.reasonSearchParams.reason,
is_paging: 1,
page: this.reasonPageInfo.current_page
}
sensitiveWordApi.getReasonListWithData(trimObject(params)).then((data)=> {
this.reasonListWithData = data.reason_list;
this.reasonPageInfo = {
current_page: data.page_info.page,
total: data.page_info.total,
per_page: data.page_info.page_size
};
this.isLoading = false;
})
},
changeWordPage(page) {
this.wordPageInfo.current_page = page;
this.searchWord()
},
getCategoryIdList() {
let categoryIdList = []
for(let i = 0; i < this.categoryListWithoutData.length; i++) {
if(this.categoryListWithoutData[i].isCheck) {
categoryIdList.push(this.categoryListWithoutData[i].id)
}
}
return categoryIdList
},
notCheckAllCategory() {
for(let i = 0; i < this.categoryListWithoutData.length; i++) {
this.categoryListWithoutData[i].isCheck = false;
}
},
checkAllCategory() {
for(let i = 0; i < this.categoryListWithoutData.length; i++) {
this.categoryListWithoutData[i].isCheck = true;
}
},
changeCategoryPage(page) {
this.categoryPageInfo.current_page = page;
this.searchCategory()
},
changeReasonPage(page) {
this.reasonPageInfo.current_page = page;
this.searchReason()
},
}
}
</script>
<style lang="scss" scoped>
.search-box {
max-width: none;
}
.underline {
text-decoration: underline;
}
.justify-end {
justify-content: flex-end;
}
.justify-space-bwtween {
justify-content: space-between;
}
.item-flex-end {
align-self: flex-end;
}
.text-ellipsis {
overflow: hidden;
max-width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
Manage.spec.js
import { expect } from 'chai'
import { shallowMount } from '@vue/test-utils'
import Vue from 'vue'
import Manage from '@/views/common/sensitiveWord/Manage.vue'
describe('Manage.vue', () => {
const Constructor = Vue.extend(Manage);
const vm = new Constructor().$mount();
it('包含data钩子', () => {
// 测试用例应该如何实现?另外,这个断言是否合理?不合理的话,应该如何写才合理呢
});
it('页面加载时,应该先加载敏感词类型列表', ()=> {
// 测试用例应该如何实现?另外,这个断言是否合理?不合理的话,应该如何写才合理呢
});
it('categoryListWithoutData应该是一个数组', ()=> {
// 测试用例应该如何实现?另外,这个断言是否合理?不合理的话,应该如何写才合理呢
})
it('点击新增按钮时,应该在新标签中打开新增敏感词页面', ()=> {
// 测试用例应该如何实现?另外,这个断言是否合理?不合理的话,应该如何写才合理呢
})
it('点击查询按钮时,应该根据筛选项获取敏感词列表', ()=> {
// 测试用例应该如何实现?另外,这个断言是否合理?不合理的话,应该如何写才合理呢
})
})
三、延伸问题
1、初次接触,不知道从哪里开始写起,是否有什么先后顺序、规律可遵循?(有的话,求分享一下关键词、或者资料链接,谢谢)