浅谈Vue组件单元测试究竟测试什么

2020-06-16 06:43:16易采站长站整理

对于这个 Item.vue ,业务逻辑是:

根据接收的id属性展示条目信息
如果用户是访客,点击 Add to Cart 按钮将重定向到登录页
如果用户已登录,点击 Add to Cart 按钮会触发 Vuex mutation ADD_TO_CART。

确定输入和输出

当你对组件做单元测试时,可将其视为一个黑盒。方法、计算属性等内部逻辑只影响输出。

因此,下一个重点是确定组件的输入和输出,因为这些也是测试的输入和输出。

Item.vue 的输入是:

id 属性
来自 Vuex 和 Vue Auth 的数据状态
用户点击按钮

输出是:

渲染后的 HTML
发送到 Vuex mutation 或者 Vue Router push 的数据

有些组件也会将表单和事件作为输入,触发事件作为输出。

测试 1: 访客点击按钮跳转路由

有一个业务逻辑是“如果用户是访客,点击 Add to Cart 按钮将重定向到登录页”。我们来写这个测试。

我们通过“shallow mount”组件来编写测试,然后找到并点击 Add to Cart 按钮。


test("router called when guest clicks button", () => {
const config = createConfig();
const wrapper = shallowMount(Item, config);
wrapper
.find("button")
.trigger("click");
// Assertion goes here
}

随后我们会加上 assertion。

不要超出输入和输出的界限

在这个测试中很容易采取的做法是在点击按钮后判断路由是否跳转到了登录页,比如:


import router from "router";

test("router called when guest clicks button", () => {
...
// 错!
const route = router.find(route => route.name === "login");
expect(wrapper.vm.$route.path).toBe(route.path);
}

虽然这确实也能测试组件的输出,但是它依赖于路由功能,这不应该是组件所关心的。

直接测试组件的输出会更好,也就是调用了

$router.push
。至于路由是否最终完成了操作,这已经超出了本测试的范畴。

因此我们可以监听路由的

push
方法,并断言它是否被登录路由对象调用。


import router from "router";

test("router called when guest clicks button", () => {
...
jest.spyOn(config.mocks.$router, "push");
const route = router.find(route => route.name === "login");
expect(spy).toHaveBeenCalledWith(route);
}

测试 2: 登录用户点击按钮后调用 vuex

接下来让我们测试业务逻辑“如果用户已登录,点击 Add to Cart 按钮将触发 Vuex mutation

ADD_TO_CART