亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

前端Vue單元測試知識點有哪些

發布時間:2021-12-20 16:32:50 來源:億速云 閱讀:149 作者:iii 欄目:開發技術

本篇內容介紹了“前端Vue單元測試知識點有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    一、為什么需要單元測試

    單元測試是用來測試項目中的一個模塊的功能,如函數、類、組件等。單元測試的作用有以下:

    • 正確性:可以驗證代碼的正確性,為上線前做更詳細的準備;

    • 自動化:測試用例可以整合到代碼版本管理中,自動執行單元測試,避免每次手工操作;

    • 解釋性:能夠為其他開發人員提供被測模塊的文檔參考,閱讀測試用例可能比文檔更完善;

    • 驅動開發、指導設計:提前寫好的單元測試能夠指導開發的API設計,也能夠提前發現設計中的問題;

    • 保證重構:測試用例可以多次驗證,當需要回歸測試時能夠節省大量時間。

    二、如何寫單元測試

    測試原則

    • 測試代碼時,只考慮測試,不考慮內部實現

    • 數據盡量模擬現實,越靠近現實越好

    • 充分考慮數據的邊界條件

    • 對重點、復雜、核心代碼,重點測試

    • 測試、功能開發相結合,有利于設計和代碼重構

    編寫步驟

    • 準備階段:構造參數,創建 spy 等

    • 執行階段:用構造好的參數執行被測試代碼

    • 斷言階段:用實際得到的結果與期望的結果比較,以判斷該測試是否正常

    • 清理階段:清理準備階段對外部環境的影響,移除在準備階段創建的 spy 等

    三、測試工具

    單元測試的工具可分為三類:

    • 測試運行器(Test Runner):可以模擬各種瀏覽器環境,自定義配置測試框架和斷言庫等,如Karma.

    • 測試框架:提供單元測試的功能模塊,常見的框架有Jest, mocha, Jasmine, QUnit.

    • 工具庫:assert, should.js, expect.js, chai.js等斷言庫,enzyme渲染庫,Istanbul覆蓋率計算。

    這里,我們將使用 Jest 作為例子。Jest 功能全面,集成了各種工具,且配置簡單,甚至零配置直接使用。

    四、Jest入門

    Jest 官網的描述是這樣的:

    Jest is a delightful JavaScript Testing Framework with a focus on simplicity.

    安裝

    yarn add --dev jest
    # or
    # npm install -D jest

    簡單示例

    從官網提供的示例開始,測試一個函數,這個函數完成兩個數字的相加,創建一個 sum.js 文件︰

    function sum(a, b) {
      return a + b;
    }
    module.exports = sum;

    然后,創建 sum.test.js 文件︰

    const sum = require('./sum');
    
    test('adds 1 + 2 to equal 3', () => {
      expect(sum(1, 2)).toBe(3);
    });
    
    package.json 里增加一個測試任務:
    {
      "scripts": {
        "test": "jest"
      }
    }

    最后,運行 yarn test 或 npm run test ,Jest將打印下面這個消息:

    PASS  ./sum.test.js
    ? adds 1 + 2 to equal 3 (5ms)

    至此,完成了一個基本的單元測試。

    注意:Jest 通過用 JSDOM 在 Node 虛擬瀏覽器環境模擬真實瀏覽器,由于是用 js 模擬 DOM, 所以 Jest 無法測試樣式 。Jest 測試運行器自動設置了 JSDOM。

    Jest Cli

    你可以通過命令行直接運行Jest(前提是jest已經加到環境變量PATH中,例如通過 yarn global add jest 或 npm install jest --global 安裝的 Jest) ,并為其指定各種有用的配置項。如:

    jest my-test --notify --config=config.json

    Jest 命令有以下常見參數:

    • --coverage 表示輸出單元測試覆蓋率,覆蓋率文件默認在 tests/unit/coverage/lcov-report/index.html;

    • --watch 監聽模式,與測試用例相關的文件更改時都會重新觸發單元測試。

    更多選項查看Jest CLI Options.

    使用配置文件

    使用 jest 命令可生成一個配置文件:

    jest --init

    過程中會有幾個選項供你選擇:

    √ Would you like to use Typescript for the configuration file? ... no
    √ Choose the test environment that will be used for testing ? jsdom (browser-like)
    √ Do you want Jest to add coverage reports? ... yes
    √ Which provider should be used to instrument code for coverage? ? babel
    √ Automatically clear mock calls and instances between every test? ... yes

    配置文件示例(不是基于上述選擇):

    // jest.config.js
    const path = require('path')
    
    module.exports = {
        preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
        rootDir: path.resolve(__dirname, './'),
        coverageDirectory: '<rootDir>/tests/unit/coverage',
        collectCoverageFrom: [
            'src/*.{js,ts,vue}',
            'src/directives/*.{js,ts,vue}',
            'src/filters/*.{js,ts,vue}',
            'src/helper/*.{js,ts,vue}',
            'src/views/**/*.{js,ts,vue}',
            'src/services/*.{js,ts,vue}'
        ]
    }

    使用 Babel

    yarn add --dev babel-jest @babel/core @babel/preset-env

    可以在工程的根目錄下創建一個babel.config.js文件用于配置與你當前Node版本兼容的Babel:

    // babel.config.js
    module.exports = {
      presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
    };

    vue-cli 中使用 Jest

    在項目中安裝 @vue/cli-plugin-unit-jest 插件,即可在 vue-cli 中使用 Jest:

    vue add unit-jest
    # or
    # yarn add -D @vue/cli-plugin-unit-jest @types/jest
    "scripts": {
        "test:unit": "vue-cli-service test:unit --coverage"
    },

    @vue/cli-plugin-unit-jest 會在 vue-cli-service 中注入命令 test:unit,默認會識別以下文件:<rootDir>/(tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)) 執行單元測試,即 tests/unit 目錄下的 .spec.(js|jsx|ts|tsx) 結尾的文件及目錄名為 __tests__ 里的所有 js(x)/ts(x) 文件。

    常見示例

    判斷值相等

    toBe() 檢查兩個基本類型是否精確匹配:

    test('two plus two is four', () => {
      expect(2 + 2).toBe(4);
    });

    toEqual() 檢查對象是否相等:

    test('object assignment', () => {
      const data = {one: 1};
      data['two'] = 2;
      expect(data).toEqual({one: 1, two: 2});
    });
    檢查類false值
    • toBeNull 只匹配 null

    • toBeUndefined 只匹配 undefined

    • toBeDefined 與 toBeUndefined 相反

    • toBeTruthy 匹配任何 if 語句為真

    • toBeFalsy 匹配任何 if 語句為假

    示例:

    test('null', () => {
      const n = null;
      expect(n).toBeNull();
      expect(n).toBeDefined();
      expect(n).not.toBeUndefined();
      expect(n).not.toBeTruthy();
      expect(n).toBeFalsy();
    });
    
    test('zero', () => {
      const z = 0;
      expect(z).not.toBeNull();
      expect(z).toBeDefined();
      expect(z).not.toBeUndefined();
      expect(z).not.toBeTruthy();
      expect(z).toBeFalsy();
    });
    數字大小比較
    test('two plus two', () => {
      const value = 2 + 2;
      expect(value).toBeGreaterThan(3);
      expect(value).toBeGreaterThanOrEqual(3.5);
      expect(value).toBeLessThan(5);
      expect(value).toBeLessThanOrEqual(4.5);
    
      // toBe and toEqual are equivalent for numbers
      expect(value).toBe(4);
      expect(value).toEqual(4);
    });

    對于比較浮點數相等,使用 toBeCloseTo 而不是 toEqual,因為你不希望測試取決于一個小小的舍入誤差。

    test('兩個浮點數字相加', () => {
      const value = 0.1 + 0.2;
      //expect(value).toBe(0.3);           這句會報錯,因為浮點數有舍入誤差
      expect(value).toBeCloseTo(0.3); // 這句可以運行
    });
    字符串比較

    可以使用正則表達式檢查:

    test('there is no I in team', () => {
      expect('team').not.toMatch(/I/);
    });
    
    test('but there is a "stop" in Christoph', () => {
      expect('Christoph').toMatch(/stop/);
    });
    數組和類數組

    你可以通過 toContain 來檢查一個數組或可迭代對象是否包含某個特定項:

    const shoppingList = [
      'diapers',
      'kleenex',
      'trash bags',
      'paper towels',
      'milk',
    ];
    
    test('the shopping list has milk on it', () => {
      expect(shoppingList).toContain('milk');
      expect(new Set(shoppingList)).toContain('milk');
    });
    異常

    還可以用來檢查一個函數是否拋出異常:

    function compileAndroidCode() {
      throw new Error('you are using the wrong JDK');
    }
    
    test('compiling android goes as expected', () => {
      expect(() => compileAndroidCode()).toThrow();
      expect(() => compileAndroidCode()).toThrow(Error);
    
      // You can also use the exact error message or a regexp
      expect(() => compileAndroidCode()).toThrow('you are using the wrong JDK');
      expect(() => compileAndroidCode()).toThrow(/JDK/);
    });

    更多使用方法參考API文檔.

    只執行當前test

    可使用 only() 方法表示只執行這個test,減少不必要的重復測試:

    test.only('it is raining', () => {
      expect(inchesOfRain()).toBeGreaterThan(0);
    });
    
    test('it is not snowing', () => {
      expect(inchesOfSnow()).toBe(0);
    });

    測試異步代碼

    回調函數

    例如,假設您有一個 fetchData(callback) 函數,獲取一些數據并在完成時調用 callback(data)。 你期望返回的數據是一個字符串 'peanut butter':

    test('the data is peanut butter', done => {
      function callback(data) {
        try {
          expect(data).toBe('peanut butter');
          done();
        } catch (error) {
          done(error);
        }
      }
    
      fetchData(callback);
    });

    使用 done() 是為了標識這個 test 執行完畢,如果沒有這個 done(),在 test 執行完畢后,我們的單元測試就結束了,這不符合我們的預期,因為callback還未調用,單元測試還沒走完。若 done() 函數從未被調用,將會提示超時錯誤。

    若 expect 執行失敗,它會拋出一個錯誤,后面的 done() 不再執行。 若我們想知道測試用例為何失敗,我們必須將 expect 放入 try 中,將 error 傳遞給 catch 中的 done 函數。 否則,最后控制臺將顯示一個超時錯誤失敗,不能顯示我們在 expect(data) 中接收的值。

    Promises

    還是使用上面的例子:

    test('the data is peanut butter', () => {
      return fetchData().then(data => {
        expect(data).toBe('peanut butter');
      });
    });

    一定不要忘記 return 結果,這樣才能確保測試和功能同時結束。
    如果是期望 Promise 被 reject, 則使用 catch 方法:

    test('the fetch fails with an error', () => {
      expect.assertions(1);
      return fetchData().catch(e => expect(e).toMatch('error'));
    });

    還可以使用 resolves 和 rejects 匹配器:

    test('the data is peanut butter', () => {
      return expect(fetchData()).resolves.toBe('peanut butter');
    });
    
    test('the fetch fails with an error', () => {
      return expect(fetchData()).rejects.toMatch('error');
    });
    Async/Await
    test('the data is peanut butter', async () => {
      const data = await fetchData();
      expect(data).toBe('peanut butter');
    });
    
    test('the fetch fails with an error', async () => {
      expect.assertions(1);
      try {
        await fetchData();
      } catch (e) {
        expect(e).toMatch('error');
      }
    });

    async/await 還可以和 resolves()/rejects() 結合使用:

    test('the data is peanut butter', async () => {
      await expect(fetchData()).resolves.toBe('peanut butter');
    });
    
    test('the fetch fails with an error', async () => {
      await expect(fetchData()).rejects.toMatch('error');
    });

    安裝和拆卸

    測試前和測試后

    在某些情況下,我們開始測試前需要做一些準備工作,然后在測試完成后,要做一些清理工作,可以使用 beforeEach 和 afterEach。
    例如,我們在每個test前需要初始化一些城市數據,test結束后要清理掉:

    beforeEach(() => {
      initializeCityDatabase();
    });
    
    afterEach(() => {
      clearCityDatabase();
    });
    
    test('city database has Vienna', () => {
      expect(isCity('Vienna')).toBeTruthy();
    });
    
    test('city database has San Juan', () => {
      expect(isCity('San Juan')).toBeTruthy();
    });

    類似的還有 beforeAll 和 afterAll,在當前spec測試文件開始前和結束后的單次執行。

    測試用例分組

    默認情況下,before 和 after 的塊可以應用到文件中的每個測試。 此外可以通過 describe 塊來將測試分組。 當 before 和 after 的塊在 describe 塊內部時,則其只適用于該 describe 塊內的測試。

    // Applies to all tests in this file
    beforeEach(() => {
      return initializeCityDatabase();
    });
    
    test('city database has Vienna', () => {
      expect(isCity('Vienna')).toBeTruthy();
    });
    
    test('city database has San Juan', () => {
      expect(isCity('San Juan')).toBeTruthy();
    });
    
    describe('matching cities to foods', () => {
      // Applies only to tests in this describe block
      beforeEach(() => {
        return initializeFoodDatabase();
      });
    
      test('Vienna <3 sausage', () => {
        expect(isValidCityFoodPair('Vienna', 'Wiener Würstchen')).toBe(true);
      });
    
      test('San Juan <3 plantains', () => {
        expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
      });
    });
    執行順序

    由于使用了 describe 進行分組,于是就有了嵌套的作用域,各生命周期的執行順序如下:

    • 外層作用域的 before 比內層的先執行,而 after 則相反;

    • 同一層級 beforeAll 比 beforeEach 先執行,after 則相反;

    beforeAll(() => console.log('1 - beforeAll'));
    afterAll(() => console.log('1 - afterAll'));
    beforeEach(() => console.log('1 - beforeEach'));
    afterEach(() => console.log('1 - afterEach'));
    test('', () => console.log('1 - test'));
    describe('Scoped / Nested block', () => {
      beforeAll(() => console.log('2 - beforeAll'));
      afterAll(() => console.log('2 - afterAll'));
      beforeEach(() => console.log('2 - beforeEach'));
      afterEach(() => console.log('2 - afterEach'));
      test('', () => console.log('2 - test'));
    });
    
    // 1 - beforeAll
    // 1 - beforeEach
    // 1 - test
    // 1 - afterEach
    // 2 - beforeAll
    // 1 - beforeEach
    // 2 - beforeEach
    // 2 - test
    // 2 - afterEach
    // 1 - afterEach
    // 2 - afterAll
    // 1 - afterAll

    mock 函數

    jest.fn() 可以用來生成一個 mock 函數,jest 可以捕獲這個函數的調用、this、返回值等,這在測試回調函數時非常有用。

    測試mock

    假設我們要測試函數 forEach 的內部實現,這個函數為傳入的數組中的每個元素調用一次回調函數。

    function forEach(items, callback) {
      for (let index = 0; index < items.length; index++) {
        callback(items[index]);
      }
    }

    為了測試此函數,我們可以使用一個 mock 函數,然后檢查 mock 函數的狀態來確保回調函數如期調用。

    const mockCallback = jest.fn(x => 42 + x);
    forEach([0, 1], mockCallback);
    
    // 此 mock 函數被調用了兩次
    expect(mockCallback.mock.calls.length).toBe(2);
    
    // 第一次調用函數時的第一個參數是 0
    expect(mockCallback.mock.calls[0][0]).toBe(0);
    
    // 第二次調用函數時的第一個參數是 1
    expect(mockCallback.mock.calls[1][0]).toBe(1);
    
    // 第一次函數調用的返回值是 42
    expect(mockCallback.mock.results[0].value).toBe(42);
    mock的返回值

    Mock 函數也可以用于在測試期間將測試值注入代碼︰

    const myMock = jest.fn();
    console.log(myMock());
    // > undefined
    
    myMock.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);
    
    console.log(myMock(), myMock(), myMock(), myMock());
    // > 10, 'x', true, true
    模擬接口返回

    假定有個從 API 獲取用戶的類。 該類用 axios 調用 API 然后返回 data,其中包含所有用戶的屬性:

    // users.js
    import axios from 'axios';
    
    class Users {
      static all() {
        return axios.get('/users.json').then(resp => resp.data);
      }
    }
    
    export default Users;

    現在,為測試該方法而不實際調用 API (使測試緩慢與脆弱),我們可以用 jest.mock(...) 函數自動模擬 axios 模塊。一旦模擬模塊,我們可為 .get 提供一個 mockResolvedValue ,它會返回假數據用于測試。

    // users.test.js
    import axios from 'axios';
    import Users from './users';
    
    jest.mock('axios');
    
    test('should fetch users', () => {
      const users = [{name: 'Bob'}];
      const resp = {data: users};
      axios.get.mockResolvedValue(resp);
    
      // or you could use the following depending on your use case:
      // axios.get.mockImplementation(() => Promise.resolve(resp))
    
      return Users.all().then(data => expect(data).toEqual(users));
    });
    mock函數的匹配器

    有了mock功能,就可以給函數增加一些自定義匹配器:

    // The mock function was called at least once
    expect(mockFunc).toHaveBeenCalled();
    
    // The mock function was called at least once with the specified args
    expect(mockFunc).toHaveBeenCalledWith(arg1, arg2);
    
    // The last call to the mock function was called with the specified args
    expect(mockFunc).toHaveBeenLastCalledWith(arg1, arg2);
    
    // All calls and the name of the mock is written as a snapshot
    expect(mockFunc).toMatchSnapshot();
    
    也可以自己通過原生的匹配器模擬,下方的代碼與上方的等價:
    // The mock function was called at least once
    expect(mockFunc.mock.calls.length).toBeGreaterThan(0);
    
    // The mock function was called at least once with the specified args
    expect(mockFunc.mock.calls).toContainEqual([arg1, arg2]);
    
    // The last call to the mock function was called with the specified args
    expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual([
      arg1,
      arg2,
    ]);
    
    // The first arg of the last call to the mock function was `42`
    // (note that there is no sugar helper for this specific of an assertion)
    expect(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);
    
    // A snapshot will check that a mock was invoked the same number of times,
    // in the same order, with the same arguments.
    expect(mockFunc.mock.calls).toEqual([[arg1, arg2]]);
    expect(mockFunc.getMockName()).toBe('a mock name');

    五、Vue Test Utils

    官網是這樣介紹 Vue Test Utils 的:

    Vue Test Utils 是 Vue.js 官方的單元測試實用工具庫。

    以下的例子均基于 vue-cli 腳手架,包括 webpack/babel/vue-loader

    測試單文件組件

    Vue 的單文件組件在它們運行于 Node 或瀏覽器之前是需要預編譯的。我們推薦兩種方式完成編譯:通過一個 Jest 預編譯器,或直接使用 webpack。這里我們選用 Jest 的方式。

    yarn add -D jest @vue/test-utils vue-jest

    vue-jest 目前并不支持 vue-loader 所有的功能,比如自定義塊和樣式加載。額外的,諸如代碼分隔等 webpack 特有的功能也是不支持的。如果要使用這些不支持的特性,你需要用 Mocha 取代 Jest 來運行你的測試,同時用 webpack 來編譯你的組件。

    處理 webpack 別名

    vue-cli 中默認使用 @ 作為 /src 的別名,在 Jest 也需要單獨配置:

    // jest.config.js
    
    module.exports = {
        moduleNameMapper: {
            '^@/(.*)$': '<rootDir>/src/$1'
        }
    }

    掛載組件

    被掛載的組件會返回到一個包裹器內,而包裹器會暴露很多封裝、遍歷和查詢其內部的 Vue 組件實例的便捷的方法。

    // test.js
    
    // 從測試實用工具集中導入 `mount()` 方法
    // 同時導入你要測試的組件
    import { mount } from '@vue/test-utils'
    import Counter from './counter'
    
    // 現在掛載組件,你便得到了這個包裹器
    const wrapper = mount(Counter)
    
    // 你可以通過 `wrapper.vm` 訪問實際的 Vue 實例
    const vm = wrapper.vm
    
    // 在控制臺將其記錄下來即可深度審閱包裹器
    // 我們對 Vue Test Utils 的探索也由此開始
    console.log(wrapper)

    在掛載的同時,可以設置組件的各種屬性:

    const wrapper = mount(Counter, {
        localVue,
        data() {
            return {
                bar: 'my-override'
            }
        },
        propsData: {
            msg: 'abc'
        },
        parentComponent: Foo, // 指定父組件
        provide: {
            foo() {
                return 'fooValue'
            }
        }
    })

    測試組件渲染出來的 HTML

    通過包裹器wrapper的相關方法,判斷組件渲染出來的HTML是否符合預期。

    import { mount } from '@vue/test-utils'
    import Counter from './counter'
    
    describe('Counter', () => {
      // 現在掛載組件,你便得到了這個包裹器
      const wrapper = mount(Counter)
    
      test('renders the correct markup', () => {
        expect(wrapper.html()).toContain('<span class="count">0</span>')
      })
    
      // 也便于檢查已存在的元素
      test('has a 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)
    })

    為了測試計數器中的文本是否已經更新,我們需要了解 nextTick。任何導致操作 DOM 的改變都應該在斷言之前 await nextTick 函數。

    it('button click should increment the count text', async () => {
      expect(wrapper.text()).toContain('0')
      const button = wrapper.find('button')
      await button.trigger('click')
      expect(wrapper.text()).toContain('1')
    })

    組件的事件

    每個掛載的包裹器都會通過其背后的 Vue 實例自動記錄所有被觸發的事件。你可以用 wrapper.emitted() 方法取回這些事件記錄。

    wrapper.vm.$emit('foo')
    wrapper.vm.$emit('foo', 123)
    
    /*
    `wrapper.emitted()` 返回以下對象:
    {
      foo: [[], [123]]
    }
    */

    然后你可以基于這些數據來設置斷言:

    // 斷言事件已經被觸發
    expect(wrapper.emitted().foo).toBeTruthy()
    
    // 斷言事件的數量
    expect(wrapper.emitted().foo.length).toBe(2)
    
    // 斷言事件的有效數據
    expect(wrapper.emitted().foo[1]).toEqual([123])

    還可以觸發子組件的事件:

    import { mount } from '@vue/test-utils'
    import ParentComponent from '@/components/ParentComponent'
    import ChildComponent from '@/components/ChildComponent'
    
    describe('ParentComponent', () => {
      test("displays 'Emitted!' when custom event is emitted", () => {
        const wrapper = mount(ParentComponent)
        wrapper.find(ChildComponent).vm.$emit('custom')
        expect(wrapper.html()).toContain('Emitted!')
      })
    })

    組件的data

    可以使用 setData() 或 setProps 設置組件的狀態數據:

    it('manipulates state', async () => {
      await wrapper.setData({ count: 10 })
    
      await wrapper.setProps({ foo: 'bar' })
    })

    模擬vue實例方法

    由于Vue Test Utils 的 setMethods() 即將廢棄,推薦使用 jest.spyOn() 方法來模擬Vue實例方法:

    import MyComponent from '@/components/MyComponent.vue'
    
    describe('MyComponent', () => {
      it('click does something', async () => {
        const mockMethod = jest.spyOn(MyComponent.methods, 'doSomething')
        await shallowMount(MyComponent).find('button').trigger('click')
        expect(mockMethod).toHaveBeenCalled()
      })
    })

    全局插件

    如果你需要安裝所有 test 都使用的全局插件,可以使用 setupFiles,先在 jest.config.js 中指定 setup 文件:

    // jest.config.js
    module.exports = {
        setupFiles: ['<rootDir>/tests/unit/setup.js']
    }

    然后在 setup.js 使用:

    // setup.js
    import Vue from 'vue'
    
    // 以下全局注冊的插件在jest中不生效,必須使用localVue
    import ElementUI from 'element-ui'
    import VueClipboard from 'vue-clipboard2'
    
    Vue.use(ElementUI)
    Vue.use(VueClipboard)
    
    Vue.config.productionTip = false

    當你只是想在某些 test 中安裝全局插件時,可以使用 localVue,這會創建一個臨時的Vue實例:

    import { createLocalVue, mount } from '@vue/test-utils'
    
    // 創建一個擴展的 `Vue` 構造函數
    const localVue = createLocalVue()
    
    // 正常安裝插件
    localVue.use(MyPlugin)
    
    // 在掛載選項中傳入 `localVue`
    mount(Component, {
      localVue
    })

    測試watch

    假如我們有一個這樣的watcher:

    watch: {
      inputValue(newVal, oldVal) {
        if (newVal.trim().length && newVal !== oldVal) {
          console.log(newVal)
        }
      }
    }

    由于watch的調用是異步的,并且在下一個tick才會調用,因此可以通過檢測watcher里的方法是否被調用來檢測watch是否生效,使用 jest.spyOn() 方法:

    describe('Form.test.js', () => {
      let cmp
      ...
    
      describe('Watchers - inputValue', () => {
        let spy
    
        beforeAll(() => {
          spy = jest.spyOn(console, 'log')
        })
    
        afterEach(() => {
          spy.mockClear()
        })
    
        it('is not called if value is empty (trimmed)', () => {
        })
    
        it('is not called if values are the same', () => {
        })
    
        it('is called with the new value in other cases', () => {
        })
      })
    })
    
    it("is called with the new value in other cases", done => {
      cmp.vm.inputValue = "foo";
      cmp.vm.$nextTick(() => {
        expect(spy).toBeCalled();
        done();
      });
    });

    第三方插件

    當我們使用一些第三方插件的時候,一般不需要關心其內部的實現,不需要測試其組件,可以使用 shallowMount 代替 mount, 減少不必要的渲染:

    import { shallowMount } from '@vue/test-utils'
    
    const wrapper = shallowMount(Component)
    wrapper.vm // 掛載的 Vue 實例
    
    還可以通過 findAllComponents 來查找第三方組件:
    import { Select } from 'element-ui'
    test('選中總部時不顯示分部和網點', async () => {
        await wrapper.setProps({
            value: {
                clusterType: 'head-quarter-sit',
                branch: '',
                site: ''
            }
        })
        // 總部不顯示分部和網點
        expect(wrapper.findAllComponents(Select)).toHaveLength(1)
    })

    六、總結

    單元測試理論

    • 單元測試能夠持續驗證代碼的正確性、驅動開發,并起到一定的文檔作用;

    • 測試時數據盡量模擬現實,只考慮測試,不考慮內部代碼;

    • 測試時充分考慮數據的邊界條件

    • 對重點、復雜、核心代碼,重點測試

    • 編寫單元測試有以下階段:準備階段、執行階段、斷言階段、清理階段;

    • 單元測試的工具可分為三類:測試運行器(Test Runner)、測試框架、工具庫。

    Jest

    • --watch 選項可以監聽文件的編碼,自動執行單元測試;

    • 測試異步代碼可以用 done 方法或 aync 函數;

    • mock函數可以捕獲這個函數的調用、this、返回值等,測試回調函數時非常有用。

    Vue Test Utils

    • 用 mount 方法掛載組件,并可自定義各種vue屬性;

    • shallowMount 方法不渲染子組件,從而加快測試速度;

    • setupFiles 可以設置全局環境,如安裝 element-ui;

    • createLocalVue 可在創建單獨的vue實例,與全局的隔離;

    “前端Vue單元測試知識點有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    vue
    AI

    鸡西市| 和田市| 武义县| 政和县| 泉州市| 阳高县| 赤水市| 丹东市| 怀集县| 五峰| 闽侯县| 柳江县| 上饶县| 邵阳县| 抚顺县| 宝丰县| 龙里县| 色达县| 顺平县| 西盟| 平罗县| 抚松县| 扎赉特旗| 德安县| 郧西县| 于都县| 磐石市| 湘西| 怀集县| 河南省| 吴江市| 镇坪县| 胶州市| 连州市| 朝阳市| 宜宾市| 永康市| 钟祥市| 汉沽区| 韶山市| 江川县|