針對 Vuex 的 Mutation 做 Unit Test

Vuex 分成 State、Mutation、Getter 與 Action 四部分,由於都是圍繞在 Data,因此都是針對 Data 做測試。

本文討論 Mutation 的 Unit Test。

Version


Vue 2.5.22
Vuex 3.0.1
Vue-test-utils 1.0.0-beta.20

Store


books-info.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { fetchBooks } from '@/api/books';

/** mutation */
const setBooks = (state, { books }) => state.books = books;

/** action */
const saveBooks = commit => ({ data }) => commit('setBooks', data);
const loadBooks = ({ commit }) => fetchBooks().then(saveBooks(commit));

/** getter */
const booksCount = ({ books }) => books.length;

export default {
namespaced: true,
state: {
books: []
},
mutations: {
setBooks
},
getters: {
booksCount
},
actions: {
loadBooks
},
};

一個典型的 Vuex store,包含 statemutationsgettersactions

第 3 行

1
2
/** mutation */
const setBooks = (state, { books }) => state.books = books;

setBooks() 為典型的 mutation,將 payload 寫入 state,該如何對這行 code 做 unit test 呢 ?

Unit Test


mutation.spec.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import store from '@/store/modules/books-info';

test('setBooks() mutation', () => {
/** arrange */
const stub = [1, 2, 3];
const state = { books: [] };

/** act */
store.mutations.setBooks(state, { books: stub });

/** assert */
expect(state.books).toBe(stub);
});

第 1 行

1
import store from '@/store/modules/books-info';

將要測試的 store import 進來。

第 3 行

1
2
3
4
5
6
7
test('setBooks() mutation', () => {
/** arrange */

/** act */

/** assert */
}

所有的 unit test 都包在 test() 的第二個參數,以 Arrow Function 表示。

test() 的第一個參數為 description,可描述 test case。

一樣使用 3A 原則寫 unit test。

第 4 行

1
2
3
/** arrange */
const stub = [1, 2, 3];
const state = { books: [] };

要測試 mutation,有兩個原則:

  1. 提供 stub 透過 mutation 寫入 state,並驗證 state 是否等於 stub
  2. 提供 fake state object 對 books state 做初始化
1
const stub = [1, 2, 3];

建立要測試的 stub。

1
const state = { books: [] };

建立 fake state object。

第 8 行

1
2
/** act */
store.mutations.setBooks(state, { books: stub });

實際執行 setBooks() mutation,並傳入剛剛在 arrange 建立的 fake state 與 stub。

因為 setBooks() mutation 的 payload 為 object,所以 unit test 時也要傳入 object

11 行

1
2
/** assert */
expect(state.books).toBe(stub);

實際讀取 books state,驗證是否等於 stub。

1
$ yarn test:unit

好mutation000

通過 unit test 得到 綠燈

Conclusion


  • Vuex 的 mutation 本質是 function,且職責很確定,因此 unit test 非常好寫
  • 由於 mutation 的職責只有修改 state,測試手法就是將 stub 傳進 mutation ,然後驗證 state 是不是等於 stub

Sample Code


完整範例可以在我的 GitHub 上找到