如何爲 Vue 項目寫單元測試

衆所周知,Vue.js 是一個非常牛逼的 JavaScript 框架,對於創建複雜功能的前端項目是非常有用的。不管是什麼項目,檢查應用是否正常工作,運行是否爲預期,是尤爲重要的。然而,爲了保證業務正常運行,我們的項目,每做一次更新,都要對所有功能做一次迴歸測試,隨着項目的增大,重複的測試工作越來越多,越來越乏味,手工測試將變成一個噁心的事情。正因如此,自動化測試誕生了,它可以隨時監測我們的代碼是否正常工作,運行結果是否符合預期。在這個教程中,我們將創建一個簡單的VueJS項目,併爲其寫一個簡單的單元測試。

我們創建一個基本的 to-do list 組件進行測試。我們將要測試的是,列表展示是否正確,用戶是否可以正常添加到 to-do list。通過這個教程,你將學會如何去爲你的組件寫一個測試,測試包括HTML展示是否正確以及用戶的操作是否能正常進行。

這個git庫是這篇文章的所有代碼。

創建項目

創建 JavaScript 項目可能是一個複雜的過程。琳琅滿目的依賴庫供我們選擇。不過還好,我們可以使用vue-cli來創建VueJS項目,它幫我們包辦一切。運行 npm install 來安裝依賴:

npm install -g vue-cli
vue init webpack project-name

在這個過程中,你可能會遇到幾個提示。大多數提示比較簡單易懂,你可以直接選擇默認選項。需要注意的是,我們需要是否安裝 vue-routerKarmaMocha的提示後輸入YES來引入這些工具。然後開始安裝依賴:

cd project-name
npm install

接下來我們執行下面的命令,這個命令將會在本地運行你的應用並在瀏覽器中打開。

npm run dev

如果你的網絡好的話,一會就裝好了。

依賴

Webpack (2.3) 是一個打包器,它可以合併打包JavaScript,CSS,HTML文件,並且提供給應用運行。Bable (v6.22) 是一個編譯器,用來把ES6編譯成ES5。目前有很多 JavaScript 標準在許多瀏覽器中還沒有被支持,所以需要將ES6轉成ES。

測試依賴

Karma (v1.4) 是一個運行時,它產生一個 Web 服務環境來運行項目代碼,並且執行測試。Mocha (v3.2) 是一個 JavaScript 測試框架。Chai (v3.5) 是一個 Mocha 可以使用的斷言庫。

在你的項目中,你可以找到下面這些目錄:buildconfignode_modulessrcstatic 和 test。對於本教程來說最重要的是src,它包括我們應用的代碼,用來測試。

第一次測試

從最基本的開始去做一般都沒錯。我們將從創建簡單的列表組件開始。在 src/components 裏創建一個新文件叫做 List.vue 並且將下面代碼寫進去。

    <template>
      <div>
        <h1>My To Do List</h1>
        </br>
        <!--displays list -->
        <ul>
          <li v-for="item in listItems">{{ item }}</li>
        </ul>
      </div>
    </template>

    <script>
    export default {
      name: 'list',
      data () {
        return {
          listItems: ['buy food', 'play games', 'sleep'],
        }
      }
    }
    </script>

在這個組件中,列表項被儲存在數組(listItems)裏面。數據被傳遞到模板,然後被遍歷(v-for),然後展現在頁面上。

當然,我們需要看到剛剛創建的列表,我們可以創建一個新的路由來展示這個組件。在src/router/index.js中創建一個路由,添加完了代碼應該是下面這樣的:

    import Vue from 'vue'
    import Router from 'vue-router'
    import Hello from '@/components/Hello'
    import List from '@/components/List'

    Vue.use(Router)

    export default new Router({
      routes: [
        {
          path: '/',
          name: 'Hello',
          component: Hello
        },
        {
          path: '/to-do',
          name: 'ToDo',
          component: List
        },
      ]
    })

現在,訪問localhost:8080/#/to-do,可以看到我們做的應用。

首先,我們要測試的是數據的正確性。在test/unit/specs目錄下創建一個List.spec.js,並且寫入下面的代碼:

    import List from '@/components/List';
    import Vue from 'vue';

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

      it('displays items from the list', () => {
          // our test goes here
      })
    })

在這個文件中,我們describingList.vue組件,並且我們創建了一個空的測試,他將要檢查這個組件的列表展示。這是一個基本的 Mocha 測試文件。

我們首先要安裝我們的Vue組件。複製下面代碼放在測試文件的'our test goes here'下面:

    // build component
    const Constructor = Vue.extend(List);
    const ListComponent = new Constructor().$mount();

我們繼承了Vue組件並且安裝這個組件。安裝組件很重要,只有這樣我們才能將通過模板來渲染HTML。也就是說,HTML已經被創建,並且我們模板中的變量(比如 item)已經被填充內容,這樣我們就可以獲取HTML了(使用$el)。

我們的組件準備好了,我們可以寫第一個斷言。在這個例子中,我們使用Chai 斷言庫提供的 'expect' 模式,還有 'should' 和 'assert'模式。將下面的代碼放到,啓動組件的後面。

    // assert that component text contains items from the list
    expect(ListComponent.$el.textContent).to.contain('play games');

之前提到過,我們可以使用ListComponent.$el來獲取組件的HTML,如果想去獲取HTML內的內容(比如 文本),我們可以使用ListComponent.$el.textContent。這個斷言用來檢查HTML列表中的文本是否和組件的data裏的數據列表吻合。

爲了檢查所有的事情都符合我們的預期,我們可以運行測試!通過 vue-cli 創建的項目,我們可以簡單的使用npm run unit來運行cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run

    npm run unit

如果測試都通過了,將會有一個綠色的列表來顯示測試報告,讓你瞭解測試都覆蓋了哪些代碼。

模擬用戶輸入

雖然前面的功能贊贊噠,但沒有多少應用只是用來展示數據。下一步我們要做到是添加新的項目到to-do list中。看這裏,我們創建了一個input框來輸入內容,然後創建一個button用來提交內容。下面是更新後的 List.vue:

    <template>
      <div>
        <h1>My To Do List</h1>
        </br>
        <input v-model="newItem" >
        <button @click="addItemToList">Add</button>
        <!-- displays list --> 
        <ul>
          <li v-for="item in listItems">{{ item }}</li>
        </ul>
      </div>
    </template>

    <script>
    export default {
      name: 'test',
      data () {
        return {
          listItems: ['buy food', 'play games', 'sleep'],
          newItem: ''
        }
      },
      methods: {
          addItemToList() {
            this.listItems.push(this.newItem);
            this.newItem = '';
          }
      }
    }
    </script>

使用v-model,輸入框裏面的內容將和newItem進行雙向綁定。當按鈕被點擊後,執行addItemToList,將newItem添加到to-do list數組裏面,並且清空newItem裏面的內容,新的項目將會被添加到列表中。

可以爲新功能寫測試文件了,創建List.spec.js,並且添加以下測試代碼。

    it('adds a new item to list on click', () => {
        // our test goes here
    })

第一步,我們需要創建我們的組件,並且模擬一個用戶在輸入框的輸入行爲。因爲 VueJs 將輸入框和 newItem 變量進行了綁定,我們可以給newItem設置內容。

    // build component
    const Constructor = Vue.extend(List);
    const ListComponent = new Constructor().$mount();

    // set value of new item
    ListComponent.newItem = 'brush my teeth';

下一步,我們需要點擊按鈕。我們需要在HTML中找到按鈕,在$el中即可找到。這是,我們可以使用querySelector,像選擇真是元素一樣選擇這個按鈕。也可以使用class(.buttonClass)、ID(#buttonID)或者標籤名(button)來選擇。

    // find button
    const button = ListComponent.$el.querySelector('button');

爲了模擬點擊,我們需要給按鈕一個新的事件對象。在測試環境中,List組件不會監聽任何事件,因此我們需要手動運行watcher

    // simulate click event
    const clickEvent = new window.Event('click');
    button.dispatchEvent(clickEvent);
    ListComponent._watcher.run();

最後,我們需要檢查我們添加的新項目是否顯示在HTML中,這個在前面已經介紹過。我們也需要檢查newItem是否被存儲在了數組裏面。

    //assert list contains new item
    expect(ListComponent.$el.textContent).to.contain('brush my teeth');
    expect(ListComponent.listItems).to.contain('brush my teeth');

下面是整個測試文件的內容:

    import List from '@/components/List';
    import Vue from 'vue';

    describe('List.vue', () => {
      it('displays items from the list', () => {
        const Constructor = Vue.extend(List);
        const ListComponent = new Constructor().$mount();
        expect(ListComponent.$el.textContent).to.contain('play games');
      })

      it('adds a new item to list on click', () => {
        // build component
        const Constructor = Vue.extend(List);
        const ListComponent = new Constructor().$mount();

        // set input value
        ListComponent.newItem = 'brush my teeth';

        // simulate click event
        const button = ListComponent.$el.querySelector('button');
        const clickEvent = new window.Event('click');
        button.dispatchEvent(clickEvent);
        ListComponent._watcher.run();

        // assert list contains new item
        expect(ListComponent.$el.textContent).to.contain('brush my teeth');
        expect(ListComponent.listItems).to.contain('brush my teeth');
      })
    })

現在跑一次這個測試,應該全是綠色的。

希望你讀這些代碼的時候思路能夠清晰,不過它對於剛剛開始接觸VueJs單元測試的人來說可讀性並不是很高。有一個VueJS實用程序庫,它將一些複雜的代碼進行了封裝。如果想使用它,可以在項目的根目錄下輸入以下命令安裝。

    npm install avoriaz

下面這個測試實際上和上面測試相同,只不過寫法上有些不同。我們使用了mount()法來安裝Vue組件,使用find()獲取按鈕,使用dispatch()來觸發點擊。

    import { mount } from 'avoriaz';
    import List from '@/components/List';
    import Vue from 'vue';

    describe('List.vue', () => {
      // previous tests ..

      it('adds new item to list on click with avoriaz', () => {
           // build component
        const ListComponent = mount(List);

        // set input value
        ListComponent.setData({
          newItem: 'brush my teeth',
        });

        // simulate click event
        const button = ListComponent.find('button')[0];
        button.dispatch('click');

        // assert list contains new item
        expect(ListComponent.text()).to.contain('brush my teeth');
        expect(ListComponent.data().listItems).to.contain('brush my teeth');
      })
    })
這個git庫是所有的代碼。
發佈了16 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章