本篇文章为大家展示了 Vue-Router如何进行单元测试,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

创建组件
我们会弄一个简单的 
Nested Route
现在定义一个路由:
import NestedRoute from "@/components/NestedRoute.vue"
export default [
 { path: "/nested-route", component: NestedRoute }
]在真实的应用中,一般会创建一个 router.js 文件并导入定义好的路由,写出来一般是这样的:
import Vue from "vue"
import VueRouter from "vue-router"
import routes from "./routes.js"
Vue.use(VueRouter)
export default new VueRouter({ routes })为避免调用 Vue.use(...) 污染测试的全局命名空间,我们将会在测试中创建基础的路由;这让我们能在单元测试期间更细粒度的控制应用的状态。
编写测试
先看点代码再说吧。我们来测试 App.vue,所以相应的增加一个 App.spec.js:
import { shallowMount, mount, createLocalVue } from "@vue/test-utils"
import App from "@/App.vue"
import VueRouter from "vue-router"
import NestedRoute from "@/components/NestedRoute.vue"
import routes from "@/routes.js"
const localVue = createLocalVue()
localVue.use(VueRouter)
describe("App", () => {
 it("renders a child component via routing", () => {
  const router = new VueRouter({ routes })
  const wrapper = mount(App, { localVue, router })
  router.push("/nested-route")
  expect(wrapper.find(NestedRoute).exists()).toBe(true)
 })
})照例,一开始先把各种模块引入我们的测试;尤其是引入了应用中所需的真实路由。这在某种程度上很理想 -- 若真实路由一旦挂了,单元测试就失败,这样我们就能在部署应用之前修复这类问题。
可以在 
另一个要注意的是这里用了 mount  而非 shallowMount。如果用了  shallowMount,则  
为使用了 mount 的大型渲染树做些变通
使用 mount  在某些情况下很好,但有时却是不理想的。比如,当渲染整个 
如果你在用 Jest,其强大的 mock 系统为此提供了一个优雅的解决方法。可以简单的 mock 掉子组件,在本例中也就是 
jest.mock("@/components/NestedRoute.vue", () => ({
 name: "NestedRoute",
 render: h => h("div")
}))使用 Mock Router
有时真实路由也不是必要的。现在升级一下 
import { shallowMount } from "@vue/test-utils"
import NestedRoute from "@/components/NestedRoute.vue"
import routes from "@/routes.js"
describe("NestedRoute", () => {
 it("renders a username from query string", () => {
  const username = "alice"
  const wrapper = shallowMount(NestedRoute)
  expect(wrapper.find(".username").text()).toBe(username)
 })
})然而我们并没有
tests/unit/NestedRoute.spec.js
NestedRoute
✕ renders a username from query string (25ms)● NestedRoute › renders a username from query string
[vue-test-utils]: find did not return .username, cannot call text() on empty Wrapper
来更新一下 
Nested Route{{ $route.params.username }}
现在报错变为了:
tests/unit/NestedRoute.spec.js
NestedRoute
✕ renders a username from query string (17ms)● NestedRoute › renders a username from query string
TypeError: Cannot read property 'params' of undefined
这是因为 $route 并不存在。 我们当然可以用一个真正的路由,但在这样的情况下只用一个 mocks 加载选项会更容易些:
it("renders a username from query string", () => {
 const username = "alice"
 const wrapper = shallowMount(NestedRoute, {
  mocks: {
   $route: {
    params: { username }
   }
  }
 })
 expect(wrapper.find(".username").text()).toBe(username)
})这样测试就能通过了。在本例中,我们没有做任何的导航或是和路由的实现相关的任何其他东西,所以 mocks 就挺好。我们并不真的关心 username 是从查询字符串中怎么来的,只要它出现就好。
测试路由钩子的策略
Vue Router 提供了多种类型的路由钩子, 称为 “navigation guards”。举两个例子如:
- 全局 guards (router.beforeEach)。在 router 实例上声明 
- 组件内 guards,比如 beforeRouteEnter。在组件中声明 
要确保这些运作正常,一般是集成测试的工作,因为需要一个使用者从一个理由导航到另一个。但也可以用单元测试检验导航 guards 中调用的函数是否正常工作,并更快的获得潜在错误的反馈。这里列出一些如何从导航 guards 中解耦逻辑的策略,以及为此编写的单元测试。
全局 guards
比方说当路由中包含 shouldBustCache 元数据的情况下,有那么一个 bustCache 函数就应该被调用。路由可能长这样:
//routes.js
import NestedRoute from "@/components/NestedRoute.vue"
export default [
 {
  path: "/nested-route",
  component: NestedRoute,
  meta: {
   shouldBustCache: true
  }
 }
]之所以使用 shouldBustCache 元数据,是为了让缓存无效,从而确保用户不会取得旧数据。一种可能的实现如下:
//router.js
import Vue from "vue"
import VueRouter from "vue-router"
import routes from "./routes.js"
import { bustCache } from "./bust-cache.js"
Vue.use(VueRouter)
const router = new VueRouter({ routes })
router.beforeEach((to, from, next) => {
 if (to.matched.some(record => record.meta.shouldBustCache)) {
  bustCache()
 }
 next()
})
export default router在单元测试中,你可能想导入 router 实例,并试图通过 router.beforeHooks[0]() 的写法调用 beforeEach;但这将抛出一个关于 next 的错误 -- 因为没法传入正确的参数。针对这个问题,一种策略是在将 beforeEach 导航钩子耦合到路由中之前,解耦并单独导出它。做法是这样的:
//router.js
export function beforeEach((to, from, next) {
 if (to.matched.some(record => record.meta.shouldBustCache)) {
  bustCache()
 }
 next()
}
router.beforeEach((to, from, next) => beforeEach(to, from, next))
export default router再写测试就容易了,虽然写起来有点长:
import { beforeEach } from "@/router.js"
import mockModule from "@/bust-cache.js"
jest.mock("@/bust-cache.js", () => ({ bustCache: jest.fn() }))
describe("beforeEach", () => {
 afterEach(() => {
  mockModule.bustCache.mockClear()
 })
 it("busts the cache when going to /user", () => {
  const to = {
   matched: [{ meta: { shouldBustCache: true } }]
  }
  const next = jest.fn()
  beforeEach(to, undefined, next)
  expect(mockModule.bustCache).toHaveBeenCalled()
  expect(next).toHaveBeenCalled()
 })
 it("busts the cache when going to /user", () => {
  const to = {
   matched: [{ meta: { shouldBustCache: false } }]
  }
  const next = jest.fn()
  beforeEach(to, undefined, next)
  expect(mockModule.bustCache).not.toHaveBeenCalled()
  expect(next).toHaveBeenCalled()
 })
})最主要的有趣之处在于,我们借助 jest.mock,mock 掉了整个模块,并用 afterEach 钩子将其复原。通过将 beforeEach 导出为一个已结耦的、普通的 Javascript 函数,从而让其在测试中不成问题。
为了确定 hook 真的调用了 bustCache 并且显示了最新的数据,可以使用一个诸如 Cypress.io 的端到端测试工具,它也在应用脚手架 vue-cli 的选项中提供了。
组件 guards
一旦将组件 guards 视为已结耦的、普通的 Javascript 函数,则它们也是易于测试的。假设我们为 
//NestedRoute.vue
对在全局 guard 中的方法照猫画虎就可以测试它了:
// ...
import NestedRoute from "@/compoents/NestedRoute.vue"
import mockModule from "@/bust-cache.js"
jest.mock("@/bust-cache.js", () => ({ bustCache: jest.fn() }))
it("calls bustCache and next when leaving the route", () => {
 const next = jest.fn()
 NestedRoute.beforeRouteLeave(undefined, undefined, next)
 expect(mockModule.bustCache).toHaveBeenCalled()
 expect(next).toHaveBeenCalled()
})Vue的优点
Vue具体轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快等优势,Vue中页面使用的是局部刷新,不用每次跳转页面都要请求所有数据和dom,可以大大提升访问速度和用户体验。
上述内容就是 Vue-Router如何进行单元测试,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注创新互联成都网站设计公司行业资讯频道。
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
分享名称:Vue-Router如何进行单元测试-创新互联
链接地址:http://www.scyingshan.cn/article/dihoii.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 