51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 508|回复: 0
打印 上一主题 下一主题

[资料] 浅谈vue单元测试最佳实践(中)

[复制链接]
  • TA的每日心情
    无聊
    1 小时前
  • 签到天数: 944 天

    连续签到: 3 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2023-6-13 10:46:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    三、开始单元测试
      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之后的结果如下,通过了单元测试。


    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-5-8 10:43 , Processed in 0.067784 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表