Tập áp dụng TDD cho dự án sử dụng VueJS

I. Tổng quan

1. TDD là gì?

"Test-Driven Development” có thể được tạm hiểu là mô hình phát triển với trọng tâm hướng về việc kiểm thử. TDD được xây dựng theo hai tiêu chí: Test-First (Kiểm thử trước) và Code-Later (Code sau)

2. Các bước tiến hành TDD

  • Viết 1 test cho hàm mới. Đảm bảo rằng test sẽ fail.
  • Chuyển qua viết code sơ khai nhất cho hàm đó để test có thể pass.
  • Tối ưu hóa đoạn code của hàm vừa viết sao cho đảm bảo test vẫn pass và tối ưu nhất cho việc lập trình kế tiếp
  • Lặp lại cho các hàm khác từ bước 1

3. Công cụ cần thiết để thực hiện test JS

Cần 4 thành phần chính như sau

  • Test Runners
  • Testing Frameworks
  • Assertion Libraries
  • Testing Plugins

Trong bài viết này mình lựa chọn lần lượt các công cụ: Karma, Mocha, Chai và Sinon

II. Tiến hành

1. Ý tưởng

Mình sẽ thực hiện 1 demo Counter nho nhỏ như hình dưới đây

2. Khởi tạo project

Mình sử dụng vue-cli để setup cho nhanh nhé :slight_smile:

npm install -g vue-cli
vue init webpack tdd-vue
cd tdd-vue
npm install
npm run dev

Mình bắt đầu với file src/components/HelloWorld.vue trước nhé. Làm rỗng file trước đã 😙

<template>
    <div></div>
</template>
<script>
<script>

3. Viết test case đầu tiên

import Vue from 'vue'
import HelloWorld from '@/components/HelloWorld'

describe('HelloWorld.vue', () => {

    it('should render correct contents', () => {
        const Constructor = Vue.extend(HelloWorld)
        const vm = new Constructor().$mount()

        expect(vm.$el.querySelector('h1').textContent)
        .to.equal('Welcome to my first TDD :)')
    })
})
  • Bạn chạy npm run unit giờ chắc chắn sẽ fail. Vì trong file HelloWorld của mình vẫn chưa có gì cả.

  • Giờ nhiệm vụ của chúng ta đó là tạo thẻ h1 chứa nội dung Welcome to my first TDD :) để pass qua test case này

<template>
  <div>
      <h1>{{ msg }}</h1>
  </div>
</template>
<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to my first TDD :)',
    }
  },
  }
}
</script>
$ npm run unit
  HelloWorld.vue
    ✓ should render correct contents
PhantomJS 2.1.1 (Linux 0.0.0): Executed 1 of 1 SUCCESS (0.044 secs / 0.005 secs)
TOTAL: 1 SUCCESS
=============================== Coverage summary ===============================
Statements   : 100% ( 1/1 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 0/0 )
Lines        : 100% ( 1/1 )
  • Ok vậy là xong test case đầu tiên.Tuy nhiên khởi tạo const vm ở mỗi test case như này có vẻ hơi "tù". Ta refactor lại và thực hiện viết test kiểm tra biến count như sau
import Vue from 'vue'
import HelloWorld from '@/components/HelloWorld'

describe('HelloWorld.vue', () => {
    let vm

    beforeEach(() => {
        const Constructor = Vue.extend(HelloWorld)
        vm = new Constructor().$mount()
    })

    it('should render correct contents', () => {
        expect(vm.$el.querySelector('h1').textContent)
        .to.equal('Welcome to my first TDD :)')
    })

    it('should has correct init counter variable', () => {
        expect(vm.$data.count).to.equal(0)
    })
})
  • Code tiếp nào
<template>
  <div>
      <h1>{{ msg }}</h1>
      <h2>{{ count }}</h2>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg: 'Welcome to my first TDD :)',
      count: 0    
    }
  },
}
</script>
$ npm run unit
  HelloWorld.vue
    ✓ should render correct contents
    ✓ should has correct init counter variable

PhantomJS 2.1.1 (Linux 0.0.0): Executed 2 of 2 SUCCESS (0.045 secs / 0 secs)
TOTAL: 2 SUCCESS
  • Làm tương tự các phần khác. Mình đã comment đầy đủ trong code. Các bạn tham khảo nhé.

  • Chạy lại test lần cuối

$ npm run unit
  ButtonComponent.vue
    ✓ should have to correct button text
    ✓ should emit event when click button

  HelloWorld.vue
    ✓ should render correct contents
    ✓ should has correct init counter variable
    ✓ should has child ButtonComponent
    ✓ should increment count
    ✓ should decrement count
    ✓ should increment count when click increment button
    ✓ should decrement count when click decrement button

PhantomJS 2.1.1 (Linux 0.0.0): Executed 9 of 9 SUCCESS (0.044 secs / 0.008 secs)

TOTAL: 9 SUCCESS
=============================== Coverage summary ===============================
Statements   : 100% ( 6/6 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 0/0 )
Lines        : 100% ( 6/6 )

Thật tuyệt vời khi nhìn thấy kết quả test xanh lè 100% như này. Chúc các bạn thành công 😙


Tham khảo:

All Rights Reserved