前端自動化測試(二)TDD與BDD 實戰todoList

基礎和配置請查看上篇文章

前端自動化測試(一)jest學習與使用


TDD開發 todoList

在src下創建文件containers 如下

在這裏插入圖片描述

TDD開發

app.vue

<template>
  <div id="app">
    <TodoList/>
  </div>
</template>

<script>
import TodoList from './containers/TodoList'

export default {
  name: 'app',
  components: {
    TodoList
  }
}
</script>
<style lang="stylus">
*{
  margin:0;
  padding 0;
}
html,body{
  height 100%;
  background :#CDCDCD;

}
</style>

先寫測試用例

todoList.test.js

import { shallowMount } from '@vue/test-utils'
import TodoList from '../../TodoList.vue'
import Undolist from '../../components/Undolist.vue'
// shallowMount淺渲染,只渲染當前組件,不渲染包含的子組件,適合單元測試,
// mount 全渲染,適合集成測試
describe('TodoList.vue', () => {
  it('TodoItem 初始化時,undoList應該爲空', () => {
    const wrapper = shallowMount(TodoList)
    const undoList = wrapper.vm.$data.undoList
    expect(undoList).toEqual([])
  })
  it('Todolist 監聽到header的add事件是,,undoList數組會增加一個內容', () => {
    const wrapper = shallowMount(TodoList)
    wrapper.vm.addUntodoItem(1)
    expect(wrapper.vm.undoList).toEqual([1])
  })
  it('Todolist 調用 UndoList 應該傳遞 list 參數', () => {
    const wrapper = shallowMount(TodoList)
    wrapper.setData({ undoList: [1, 2, 3] })
    const undolist = wrapper.find(Undolist)
    const list = undolist.props('list')
    expect(list).toEqual([1, 2, 3])
  })

  it('Todolist 調用 delUndoItem方法 undoList列表內容會減少一個 ', () => {
    const wrapper = shallowMount(TodoList)
    wrapper.setData({ undoList: [1, 2, 3] })
    wrapper.vm.delUndoItem(1)
    expect(wrapper.vm.undoList).toEqual([1, 3])
  })

todoList.vue

<template>
  <div class="todoList">
    <Header @add="addUntodoItem"></Header>
    <UndoList @delUndoItem="delUndoItem" :list="undoList"></UndoList>
  </div>
</template>

<script>
import Header from './components/Header'
import UndoList from './components/UndoList'
export default {
  name: 'TodoList',
  components: {
    Header,
    UndoList
  },

  data () {
    return {
      undoList: []
    }
  },
  methods: {
    addUntodoItem (data) {
      this.undoList.push(data)
    },
    delUndoItem (data) {
      this.undoList.splice(data, 1)
    }
  }

}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus">

.todoList{
  width :100%;
  height :100%
}
</style>

組件

header.test.js

import { shallowMount } from '@vue/test-utils'
import Header from '../../components/Header.vue'
// shallowMount淺渲染,只渲染當前組件,不渲染包含的子組件,適合單元測試,
// mount 全渲染,適合集成測試

describe('Header.vue', () => {
  it('Header 樣式發送改變, 做提示', () => {
    const wrapper = shallowMount(Header)

    // 生成快照,當頁面樣式寫好後可以添加快照,用於提示
    expect(wrapper).toMatchSnapshot()
  })
  it('header 包含 input 框', () => {
    const wrapper = shallowMount(Header)
    const input = wrapper.find('[data-test="input"]')
    // 判斷input原生是否存在
    expect(input.exists()).toBe(true)
  })

  it('input 框 初始內容爲空', () => {
    const wrapper = shallowMount(Header)

    const inputValue = wrapper.vm.$data.inputValue
    expect(inputValue).toBe('')
  })

  it('Header 中 input 框 值發送變化,數據應該跟着變化', () => {
    const wrapper = shallowMount(Header)
    const input = wrapper.find('[data-test="input"]')
    input.setValue('TodoList')
    const inputValue = wrapper.vm.$data.inputValue
    expect(inputValue).toBe('TodoList')
  })

  it('Header 中 input 框 無內容時,按回車不觸發事件', () => {
    const wrapper = shallowMount(Header)
    const input = wrapper.find('[data-test="input"]')
    input.setValue('')
    input.trigger('keyup.enter')
    // 是否向父組件提交add事件
    expect(wrapper.emitted().add).toBeFalsy()
  })

  it('Header 中 input 框 有內容時,按回車觸發事件 同時清空', () => {
    const wrapper = shallowMount(Header)
    const input = wrapper.find('[data-test="input"]')
    input.setValue('Todolist')
    input.trigger('keyup.enter')
    const inputValue = wrapper.vm.inputValue
    // 是否向父組件提交add事件
    expect(wrapper.emitted().add).toBeTruthy()
    expect(inputValue).toBe('')
  })
})

header.vue

<template>
  <div class="header">
    <div class="title">TodoList</div>
    <input
    class="header-input"
     type="text"
    data-test="input"
    @keyup.enter="add"
     v-model="inputValue"
     placeholder="todoItem"
     >
  </div>
</template>

<script>
export default {
  name: 'Header',
  data () {
    return {
      inputValue: ''
    }
  },
  methods: {
    add () {
      if (this.inputValue) {
        this.$emit('add', this.inputValue)
        this.inputValue = ''
      }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus">
.header{
  height :60px;
  background :#666;
  display :flex;
  justify-content :center;
  align-items :center;
}
.title{
  font-size :40px;
  color :#fff;
  margin-right :100px;
}
.header-input{
  height :20px;
  text-indent 10px;
  outline :none;
  width :300px;
}
</style>

Undolist.test.js

import { shallowMount } from '@vue/test-utils'
import UndoList from '../../components/UndoList.vue'  

  describe('Undolist.vue',()=>{
    it('UndoList 參數爲[],count值爲0',()=>{
      const wrapper = shallowMount(UndoList,{
        propsData:{list:[]}
      })
      const countElem = wrapper.find('[data-test="count"]')
      const ListTtems = wrapper.findAll('[data-test="item"]')
      expect(countElem.text()).toEqual('0')
      expect(ListTtems.length).toEqual(0)
    })

    it('UndoList 參數爲[1,2,3],count值爲3, 且列表有內容, 且存在刪除按鈕',()=>{
      const wrapper = shallowMount(UndoList,{
        propsData:{list:[1,2,3]}
      })
      const countElem = wrapper.find('[data-test="count"]')
      const ListTtems = wrapper.findAll('[data-test="item"]')
      const delBtns = wrapper.findAll('[data-test="delBtn"]')
      expect(countElem.text()).toEqual('3')
      expect(ListTtems.length).toEqual(3)
      expect(delBtns.length).toEqual(3)
    })

    it('刪除按鈕被點擊時,向外觸發刪除事件',()=>{
      const wrapper = shallowMount(UndoList,{
        propsData:{list:[1,2,3]}
      })
      // 找到第2個刪除按鈕
      const delBtns = wrapper.findAll('[data-test="delBtn"]').at(1)
      delBtns.trigger('click')
       expect(wrapper.emitted().delUndoItem).toBeTruthy()
    })
  })

undolist.vue

<template>
  <div class="undolist">
    <div class="undoList-title">
      <p>正在進行</p>
        <div data-test="count" class="count">{{list.length}}</div>
    </div>
    <ul class="item-wrap">
      <li data-test="item"
      class="item"
      v-for="(item,index) in list"
      :key="index"
      >
      {{item}}
      <span class="delBtn" data-test="delBtn" @click="delUndolist(index)"> - </span>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'Undulist',
  props: {
    list: {
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data () {
    return {

    }
  },
  methods: {
    delUndolist (data) {
      this.$emit('delUndoItem', data)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="stylus">
.undoList-title{
  display : flex;
  justify-content :space-between;
  align-items center;
  width :500px;
  margin : 50px auto;
  text-align center;
}
.undoList-title>p{
  font-size :30px;
  font-weight :bold;
}
.count{
  background :#E6E6FA;
  width :20px;
  height 20px;
  border-radius :50%;
  color: #666;
  font-size: 14px;
}
.item-wrap{
   width :500px;
  margin : 0 auto;
  padding :0;
 
}
.item{
   text-align center;
  display : flex;
  justify-content :space-between;
  padding : 10px 20px;
  box-sizing :border-box;
  align-items center;
  background :rgb(245,245,245);
  margin-bottom :20px;
  border-radius :5px;
  border-left :5px solid  #629A9C
}
.delBtn{
   background :#ccc;
  width :20px;
  height 20px;
  border-radius :50%;
  color: #fff;
  line-height :20px;
  font-size: 14px;
}
</style>

BDD實戰示例

下列就是根據上述寫好的,來測試,這裏就示例一下,

it(`
	1.用戶在輸入框中輸入了內容,
	2.用戶會點擊回車按鈕
	3.列表項應該增加用戶輸入內容的列表項
	`,()=>{
    const wrapper = mount(todoList)
    const inputElem = wrapper.find('[data-test="input"]')
    const content = "toDoList
    inputElem.setValue(content)
    inputElem.trigger('change')
    inputElem.tigger('keyup.enter')
    const listItems = wrapper.findAll('[data-test=item]')
    expect(listItems.length).toBe(1)
    expect(listItems.at(0).text()).toContain(content)
})

是否發現異常繁瑣,TDD開發模式更適用於開發,類似方法函數庫,對於數據的處理,對於這種顯示組件,更加推薦於

BDD的開發方式,這樣既有了測試,也不會增加過多的工作負擔,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章