vue单元测试最佳实践(中)

发表于:2023-6-13 09:32

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:无名    来源:稀土掘金

  三、开始单元测试
  1、整合的官方demo
  //src\components\hCounter\counter.vue
  <template>
    <div>
      <span class="desc">{{ desc }}</span>
      <span class="count">{{ count }}</span>
      <button @click="increment">Increment</button>
    </div>
  </template>
  <script>
  export default {
      data() {
        return {
          count: 0
        }
      },
      props: {
        desc: {
          type: String, 
          default: "Counter"
        }
      },
      methods: {
        increment() {
          this.count++
        }
      }
    }
  </script>
  2、编写单元测试用例
  //src\components\__test__\counter.spec.js
  import { mount } from '@vue/test-utils'
  import Counter from '@/components/hCounter/counter';
  describe('Counter', () => {
    // 现在挂载组件,你便得到了这个包裹器
    const wrapper = mount(Counter, { 
      propsData: { 
        desc: 'I am a counter'
      }
    })
    console.log('wrapper.vm.desc' , wrapper.vm.desc)
    console.log('wrapper.vm.count' , wrapper.vm.count)
    console.log('options.attachedToDocument' , wrapper.options.attachedToDocument)
    // console.log('wrapper.element' , wrapper.element)
    it('renders the desc', () => {
      expect(wrapper.html()).toContain('I am a counter')
    });
    it('renders the correct markup', () => {
      expect(wrapper.html()).toContain('<span class="count">0</span>')
    })
    // 也便于检查已存在的元素
    it('has a button', () => {
      expect(wrapper.find('button').exists()).toBe(true)
      // console.log(expect(wrapper.find('button')))
      // expect(wrapper.contains('button')).toBe(true)
    })
    //模拟用户交互
    //用户点击按钮则计数器增加递增,首先通过wrapper.find()定位改按钮,改方法返回一个该按钮元素的包裹器,然后对按钮包裹器调用.trigger模拟操作
    it('button click should increment the count', () => {
      expect(wrapper.vm.count).toBe(0)
      const button = wrapper.find('button')
      button.trigger('click')
      expect(wrapper.vm.count).toBe(1)
    })
    it('set count to 100', async () => {
      await wrapper.setData({'count': 100});
      expect(wrapper.vm.count).toBe(100)
    })
    //为了测试计数器中的文本是否更新,需要使用异步nextTick await
    //任何导致操作DOM的改变都应该在断言之前await
    it('button click should increment the count text', async () => {
      expect(wrapper.text()).toContain('1')
      const button = wrapper.find('button')
      await button.trigger('click')
      expect(wrapper.text()).toContain('2')
    })
  })
  3、对UI单元测试的建议
  对于 UI 组件来说,我们不推荐一味追求行级覆盖率,因为它会导致我们过分关注组件的内部实现细节,从而导致琐碎的测试。
  取而代之的是,我们推荐把测试撰写为断言你的组件的公共接口,并在一个黑盒内部处理它。一个简单的测试用例将会断言一些输入 (用户的交互或 prop 的改变) 提供给某组件之后是否导致预期结果 (渲染结果或触发自定义事件)。
  比如,对于每次点击按钮都会将计数加一的 Counter 组件来说,其测试用例将会模拟点击并断言渲染结果会加 1。该测试并没有关注 Counter 如何递增数值,而只关注其输入和输出。
  该提议的好处在于,即便该组件的内部实现已经随时间发生了改变,只要你的组件的公共接口始终保持一致,测试就可以通过。
  4、某项目首页tab的单元测试
  大致的逻辑上是,未登录的时候有4个tab分别是主页、产品介绍、案例展示、联系我们。
  登陆之前:
  登陆之后从home页返回之后会把主页去掉,新的tab是返回系统、产品介绍、业务指南、培训视频、案例展示、联系我们,且点击返回系统会根据角色跳转到不同的页面。
  完整的单元测试用例如下~
  import { mount, createLocalVue } from '@vue/test-utils'
  import loginHeader from '@/components/loginHeader'
  import VueRouter from 'vue-router'
  const localVue = createLocalVue()
  localVue.use(VueRouter)
  const router = new VueRouter()
  describe('loginHeader',  () => {
      const wrapperNotLogin = mount(loginHeader, {
          localVue,
          router
      });
      it('未登录之前的tab展示', () => {
          const loginTabWrap = wrapperNotLogin.find('.login-tab-wrap');
          const tabsArr = ['主页', '产品介绍', '案例展示', '联系我们'];
          for(let i = 1; i < 5; i++) {
              const findDom = loginTabWrap.findAll('div').at(i);
              expect(findDom.html()).toContain(tabsArr[i-1])
          }
      });
      //模拟登陆之后的情况
      sessionStorage.setItem('objUser', 'yes')
      sessionStorage.setItem('system.route.path.type', 'PLAN_MANAGER')
      const wrapperLogin = mount(loginHeader, {
          mocks: {
              $route: {//伪造路由
                  path: '/home'
              },
              $router: {}
          }
      });
      it('登陆成功且是计划管理人身份', () => {
          const loginTabWrap = wrapperLogin.find('.login-tab-wrap');
          const tabsArr = ['返回系统', '产品介绍', '业务指南', '培训视频', '案例展示', '联系我们'];
          for(let i = 1; i < 7; i++) {
              const findDom = loginTabWrap.findAll('div').at(i);
              expect(findDom.html()).toContain(tabsArr[i-1])
          }
      });
      it('when system.route.path.typ == PLAN_MANAGER tabsArr[0].toRouter == /absProductManage/index?active=1', () => {
          expect(wrapperLogin.vm.tabArr[0].toRouter).toBe('/absProductManage/index?active=1')
      });
    
  })
  npm run test之后的结果如下,通过了单元测试。
  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号