Vuex 之单元测试[译]

更新日期: 2019-12-28阅读: 2.1k标签: 测试

原文:https://lmiller1990.github.io/vue-testing-handbook/testing-vuex.html

通常来说 Vue 组件会在以下方面和 Vuex 发生交互:

commit 一个 mutation
dispatch 一个 action
通过 $store.state   或 getters 访问 state

要针对 Vuex 进行的单元测试,都是基于 Vuex store 的当前 state 来断言组件行为是否正常的;并不需要知道 mutators、actions 或 getters 的具体实现。


1 - 测试 Mutations

由于 mutations 就是普通的 JavaScript 函数,所以单独地测试它们非常容易。

mutations 一般遵循一套模式:取得一些数据,可能进行一些处理,然后将数据赋值给 state。

比如一个 ADD_POST   mutation 的概述如下:一旦被实现,它将从 payload 中获取一个   post  对象,并将   post.id   添加到   state.postIds   中;它也会将那个 post 对象以   post.id   为 key 添加到   state.posts   对象中。这即是在应用中使用 Vuex 的一个通常的模式。

我们将使用 TDD 进行开发。mutation 是这样开头的:

export default {
  SET_POST(state, { post }) {

  }
}

开始写测试,并让报错信息指引我们的开发:

import mutations from "@/store/mutations.js"

describe("SET_POST", () => {
  it("adds a post to the state", () => {
    const post = { id: 1, title: "Post" }
    const state = {
      postIds: [],
      posts: {}
    }

    mutations.SET_POST(state, { post })

    expect(state).toEqual({
      postIds: [1],
      posts: { "1": post }
    })
  })
})

以 yarn test:unit   运行测试将产生以下错误信息:

FAIL  tests/unit/mutations.spec.js
 SET_POST › adds a post to the state

  expect(received).toEqual(expected)

  Expected value to equal:
    {"postIds": [1], "posts": {"1": {"id": 1, "title": "Post"}}}
  Received:
    {"postIds": [], "posts": {}}

让我们从将 post.id   加入   state.postIds   开始:

export default {
  SET_POST(state, { post }) {
    state.postIds.push(post.id)
  }
}

现在 yarn test:unit   会产生:

Expected value to equal:
  {"postIds": [1], "posts": {"1": {"id": 1, "title": "Post"}}}
Received:
  {"postIds": [1], "posts": {}}

postIds   看起来挺好了。现在我们只需要将 post 加入   state.posts 。限于 Vue 反应式系统的工作方式我们无法简单地写成   post[post.id] = post   来添加 post。基本上,你需要使用   Object.assign   或   ...   操作符创建一个新的对象。此处我们将使用   ...   操作符将 post 赋值到   state.posts :

export default {
  SET_POST(state, { post }) {
    state.postIds.push(post.id)
    state.posts = { ...state.posts, [post.id]: post }
  }
}

测试通过!


2 - 测试 actions

单独地测试 actions 是非常容易的。这和单独地测试 mutations 非常之相似。

同样的,我们会遵循一个通常的 Vuex 模式创建一个 action:

发起一个向 api 的异步请求

对数据进行一些处理(可选)

根据 payload 的结果 commit 一个 mutation

这里有一个 认证   action,用来将 username 和 password 发送到外部 API 以检查它们是否匹配。然后其认证结果将被用于通过 commit 一个   SET_AUTHENTICATED   mutation 来更新 state,该 mutation 将认证结果作为 payload。

import axios from "axios"

export default {
  async authenticate({ commit }, { username, password }) {
    const authenticated = await axios.post("/api/authenticate", {
      username, password
    })

    commit("set_authenticated", authenticated)
  }
}

action 的测试应该断言:

是否使用了正确的 API 端?

payload 是否正确?

根据结果,是否有正确的 mutation 被 commit

让我们进行下去并编写测试,并让报错信息指引我们。

2.1 - 编写测试

describe("authenticate", () => {
  it("authenticated a user", async () => {
    const commit = jest.fn()
    const username = "alice"
    const password = "password"

    await actions.authenticate({ commit }, { username, password })

    expect(url).toBe("/api/authenticate")
    expect(body).toEqual({ username, password })
    expect(commit).toHaveBeenCalledWith(
      "SET_AUTHENTICATED", true)
  })
})

因为 axios   是异步的,为保证 Jest 等到测试完成后才执行,我们需要将其声明为   async  并在其后   await   那个   actions.authenticate   的调用。不然的话(译注:即假如不使用 async/await 而仅仅将 3 个   expect   断言放入异步函数的   then()   中)测试会早于   expect 断言完成,并且我们将得到一个常绿的 -- 一个不会失败的测试。

运行以上测试会给我们下面的报错信息:

FAIL  tests/unit/actions.spec.js
   authenticate › authenticated a user

    SyntaxError: The string did not match the expected pattern.

      at XMLHttpRequest.open (node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:482:15)
      at dispatchXhrRequest (node_modules/axios/lib/adapters/xhr.js:45:13)
      at xhrAdapter (node_modules/axios/lib/adapters/xhr.js:12:10)
      at dispatchRequest (node_modules/axios/lib/core/dispatchRequest.js:59:10)

这个错误来自 axios   的某处。我们发起了一个对   /api...   的请求,并且因为我们运行在一个测试环境中,所以并不是真有一个服务器在处理请求,这就导致了错误。我们也没有定义   url   或   body   -- 我们将在解决掉   axios   错误后做那些。

因为使用了 Jest,我们可以用 jest.mock   容易地 mock 掉 API 调用。我们将用一个 mock 版本的   axios   代替真实的,使我们能更多地控制其行为。Jest 提供了   ES6 Class Mocks ,非常适于 mock   axios 。

axios   的 mock 看起来是这样的:

let url = ''
let body = {}

jest.mock("axios", () => ({
  post: (_url, _body) => {
    return new Promise((resolve) => {
      url = _url
      body = _body
      resolve(true)
    })
  }
}))

我们将 url   和   body   保存到了变量中以便断言正确的时间端点接收了正确的 payload。因为我们不想实现真正的端点,用一个理解 resolve 的 promise 模拟一次成功的 API 调用就够了。

yarn unit:pass   现在测试通过了!

2.2 - 测试 API Error

咱仅仅测试过了 API 调用成功的情况,而测试所有产出的可能情况也是重要的。让我们编写一个测试应对发生错误的情况。这次,我们将先编写测试,再补全实现。

测试可以写成这样:

it("catches an error", async () => {
  mockError = true

  await expect(actions.authenticate({ commit: jest.fn() }, {}))
    .rejects.toThrow("API Error occurred.")
})

我们要找到一种强制 axios   mock 抛出错误的方法。正如   mockError   变量代表的那样。将  axios   mock 更新为:

let url = ''
let body = {}
let mockError = false

jest.mock("axios", () => ({
  post: (_url, _body) => {
    return new Promise((resolve) => {
      if (mockError)
        throw Error()

      url = _url
      body = _body
      resolve(true)
    })
  }
}))

只有当一个 ES6 类 mock 作用域外的(out-of-scope)变量以 mock   为前缀时,Jest 才允许访问它。现在我们简单地赋值   mockError = true   然后   axios   就会抛出错误了。

运行该测试给我们这些报错:

FAIL  tests/unit/actions.spec.js
 authenticate › catchs an error

  expect(function).toThrow(string)

  Expected the function to throw an error matching:
    "API Error occurred."
  Instead, it threw:
    Mock error

成功的抛出了一个错误... 却并非我们期望的那个。更新 authenticate   以达到目的:

export default {
  async authenticate({ commit }, { username, password }) {
    try {
      const authenticated = await axios.post("/api/authenticate", {
        username, password
      })

      commit("SET_AUTHENTICATED", authenticated)
    } catch (e) {
      throw Error("API Error occurred.")
    }
  }
}

现在测试通过了。

2.3 - 改良

现在你知道如何单独地测试 actions 了。至少还有一项潜在的改进可以为之,那就是将 axiosmock 实现为一个   manual mock (https://jestjs.io/docs/en/manual-mocks)。这包含在   node_modules   的同级创建一个   __mocks__   目录并在其中实现 mock 模块。Jest 将自动使用   __mocks__   中的 mock 实现。在 Jest 站点和因特网上有大量如何做的例子。


3 - 测试 getters

getters 也是普通的 JavaScript 函数,所以单独地测试它们同样非常容易;所用技术类似于测试 mutations 或 actions。

我们考虑一个用两个 getters 操作一个 store 的案例,看起来是这样的:

const state = {
  dogs: [
    { name: "lucky", breed: "poodle", age: 1 },
    { name: "pochy", breed: "dalmatian", age: 2 },
    { name: "blackie", breed: "poodle", age: 4 }
  ]
}

对于 getters 我们将测试:

poodles : 取得所有   poodles

poodlesByAge : 取得所有   poodles ,并接受一个年龄参数

3.1 - 创建 getters

首先,创建 getters。

export default {
  poodles: (state) => {
    return state.dogs.filter(dog => dog.breed === "poodle")
  },

  poodlesByAge: (state, getters) => (age) => {
    return getters.poodles.filter(dog => dog.age === age)
  }
}

并没有什么特别令人兴奋的 -- 记住 getter 可以接受其他的 getters 作为第二个参数。因为我们已经有一个 poodles   getter 了,可以在   poodlesByAge   中复用它。通过在   poodlesByAge   返回一个接受参数的函数,我们可以向 getters 中传入参数。 poodlesByAge   getter 用法是这样的:

computed: {
  puppies() {
    return this.$store.getters.poodlesByAge(1)
  }
}

让我们从测试 poodles   开始吧。

3.2 - 编写测试

鉴于一个 getter 只是一个接收一个 state   对象作为首个参数的 JavaScript 函数,所以测试起来非常简单。我将把测试写在   getters.spec.js   文件中,代码如下:

import getters from "../../src/store/getters.js"

const dogs = [
  { name: "lucky", breed: "poodle", age: 1 },
  { name: "pochy", breed: "dalmatian", age: 2 },
  { name: "blackie", breed: "poodle", age: 4 }
]
const state = { dogs }

describe("poodles", () => {
  it("returns poodles", () => {
    const actual = getters.poodles(state)

    expect(actual).toEqual([ dogs[0], dogs[2] ])
  })
})

Vuex 会自动将 state   传入 getter。因为我们是单独地测试 getters,所以还得手动传入   state 。除此之外,我们就是在测试一个普通的 JavaScript 函数。

poodlesByAge   则更有趣一点了。传入一个 getter 的第二个参数是其他   getters 。我们正在测试的是   poodlesByAge ,所以我们不想将   poodles   的实现牵扯进来。我们通过 stub 掉   getters.poodles   取而代之。这将给我们对测试更细粒度的控制。

describe("poodlesByAge", () => {
  it("returns poodles by age", () => {
    const poodles = [ dogs[0], dogs[2] ]
    const actual = getters.poodlesByAge(state, { poodles })(1)

    expect(actual).toEqual([ dogs[0] ])
  })
})

不同于向 getter 传入真实的 poodles (译注:刚刚测试过的另一个 getter),我们传入的是一个它可能返回的结果。因为之前写过一个测试了,所以我们知道它是工作正常的。这使得我们把测试逻辑单独聚焦于   poodlesByAge 。

async   的 getters 也是可能的。它们可以通过和测试   async   actions 的相同技术被测试。


4 - 测试组件内的 Vuex:state 和 getters

现在来看看 Vuex 在实际组件中的表现。

4.1 - 使用 createLocalVue   测试   $store.state

在一个普通的 Vue 应用中,我们使用 Vue.use(Vuex)   来安装 Vuex 插件,并将一个新的 Vuex store 传入 app 中。如果我们也在一个单元测试中做同样的事,那么,所有单元测试都得接收那个 Vuex store,尽管测试中根本用不到它。 vue-test-utils   提供了一个   createLocalVue   方法,用来为测试提供一个临时   Vue   实例。让我们看看如何使用它。首先,是一个基于 store 的 state 渲染出一个 username 的   <ComponentWithGetters>   组件。

<template>
  <div>
    <div class="username">
      {{ username }}
    </div>
  </div>
</template>

<script>
export default {
  name: "ComponentWithVuex",

  data() {
    return {
      username: this.$store.state.username
    }
  }
}
</script>

我们可以使用 createLocalVue   创建一个临时的   Vue   实例,并用其安装 Vuex。而后我们将一个新的   store   传入组件的加载选项中。完整的测试看起来是这样的:

import Vuex from "vuex"
import { shallowMount, createLocalVue } from "@vue/test-utils"
import ComponentWithVuex from "@/components/ComponentWithVuex.vue"

const localVue = createLocalVue()
localVue.use(Vuex)

const store = new Vuex.Store({
  state: {
    username: "alice"
  }
})

describe("ComponentWithVuex", () => {
  it("renders a username using a real Vuex store", () => {
    const wrapper = shallowMount(ComponentWithVuex, {
      store,
      localVue
    })

    expect(wrapper.find(".username").text()).toBe("alice")
  })
})

测试通过。创建一个新的 localVue   实例引入了一些样板文件(boilerplate),并且测试也很长。如果你有好多使用了 Vuex store 的组件要测试,一个替代方法是使用   mocks   加载选项,用以简化 store 的 mock。

4.2 - 使用一个 mock 的 store

通过使用 mocks   加载选项,可以 mock 掉全局的   $store   对象。这意味着你不需要使用   createLocalVue ,或创建一个新的 Vuex store 了。使用此项技术,以上测试可以重写成这样:

it("renders a username using a mock store", () => {
  const wrapper = shallowMount(ComponentWithVuex, {
    mocks: {
      $store: {
        state: { username: "alice" }
      }
    }
  })

  expect(wrapper.find(".username").text()).toBe("alice")
})

我个人更喜欢这种实现。所有必须的数据被声明在测试内部,同时它也更紧凑一点儿。当然两种技术都很有用,并没有哪种更好哪种更差之分。

4.3 - 测试 getters

使用上述技术, getters   同样易于测试。首先,是用于测试的组件:

<template>
  <div class="fullname">
    {{ fullname }}
  </div>
</template>

<script>
export default {
  name: "ComponentWithGetters",

  computed: {
    fullname() {
      return this.$store.getters.fullname
    }
  }
}
</script>

我们想要断言组件正确地渲染了用户的 fullname 。对于该测试,我们不关心   fullname   来自何方,组件渲染正常就行。

先看看用真实的 Vuex store 和 createLocalVue ,测试看起来是这样的:

const localVue = createLocalVue()
localVue.use(Vuex)

const store = new Vuex.Store({
  state: {
    firstName: "Alice",
    lastName: "Doe"
  },

  getters: {
    fullname: (state) => state.firstName + " " + state.lastName
  }
})

it("renders a username using a real Vuex getter", () => {
  const wrapper = shallowMount(ComponentWithGetters, { store, localVue })

  expect(wrapper.find(".fullname").text()).toBe("Alice Doe")
})

测试很紧凑 -- 只有两行代码。不过也引入了很多设置代码 -- 我们基本上重建了 Vuex store。一个替代方法是引入有着真正 getters 的真实的 Vuex store。这将引入测试中的另一项依赖,当开发一个大系统时,Vuex store 可能由另一位程序员开发,也可能尚未实现。

让我看看使用 mocks   加载选项编写测试的情况:

it("renders a username using computed mounting options", () => {
  const wrapper = shallowMount(ComponentWithGetters, {
    mocks: {
      $store: {
        getters: {
          fullname: "Alice Doe"
        }
      }
    }
  })

  expect(wrapper.find(".fullname").text()).toBe("Alice Doe")
})

现在全部所需的数据都包含在测试中了。太棒了!我特喜欢这个,因为测试是全包含的(fully contained),理解组件应该做什么所需的所有知识都都包含在测试中。

使用 computed   加载选项,我们甚至能让测试变得更简单。

4.4 - 用 computed   来模拟 getters

getters 通常被包裹在 computed   属性中。请记住,这个测试就是为了在给定 store 中的当前 state 时,确保组件行为的正确性。我们不测试   fullname   的实现或是要瞧瞧   getters   是否工作。这意味着我们可以简单地替换掉真实 store,或使用   computed   加载选项 mock 掉 store。测试可以重写为:

it("renders a username using computed mounting options", () => {
  const wrapper = shallowMount(ComponentWithGetters, {
    computed: {
      fullname: () => "Alice Doe"
    }
  })

  expect(wrapper.find(".fullname").text()).toBe("Alice Doe")
})

这比之前两个测试更简洁了,并且仍然表达了组件的意图。

4.5 - mapState   和   mapGetters   辅助选项

上述技术都能与 Vuex 的 mapState   和   mapGetters   辅助选项结合起来工作。我们可以将  ComponentWithGetters   更新为:

import { mapGetters } from "vuex"

export default {
  name: "ComponentWithGetters",

  computed: {
    ...mapGetters([
      'fullname'
    ])
  }
}

测试仍然通过。


5 - 测试组件内的 Vuex:mutations 和 actions

刚刚讨论过测试使用了 $store.state   和   $store.getters   的组件,这两者都用来将当前状态提供给组件。而当断言一个组件正确 commit 了一个 mutation 或 dispatch 了一个 action 时,我们真正想做的是断言   $store.commit   和   $store.dispatch   以正确的处理函数(要调用的 mutation 或 action)和 payload 被调用了。

要做到这个也有两种刚才提及的方式。一种是籍由 createLocalVue   使用一个真正的 Vuex store,另一种是使用一个 mock store。让我们再次审视它们,这次是在 mutations 和 actions 的语境中。

5. 1 - 创建组件

在这些例子里,我们将测试一个 <ComponentWithButtons>   组件:

<template>
  <div>
    <button
      class="commit"
      @click="handleCommit">
      Commit
    </button>

    <button
      class="dispatch"
      @click="handleDispatch">
      Dispatch
    </button>

    <button
      class="namespaced-dispatch"
      @click="handleNamespacedDispatch">
      Namespaced Dispatch
    </button>
  </div>
</template>

<script>
export default {
  name: "ComponentWithButtons",

  methods: {
    handleCommit() {
      this.$store.commit("testMutation", { msg: "Test Commit" })
    },

    handleDispatch() {
      this.$store.dispatch("testAction", { msg: "Test Dispatch" })
    },

    handleNamespacedDispatch() {
      this.$store.dispatch("namespaced/very/deeply/testAction", { msg: "Test Namespaced Dispatch" })
    }
  }
}
</script>

5.2 - 用一个真正的 Vuex store 测试 mutation

让我们先来编写一个测试 mutation 的 ComponentWithButtons.spec.js 。请记住,我们要验证两件事:

正确的 mutation 是否被 commit 了?

payload 正确吗?

我们将使用 createLocalVue   以避免污染全局 Vue 实例。

import Vuex from "vuex"
import { createLocalVue, shallowMount } from "@vue/test-utils"
import ComponentWithButtons from "@/components/ComponentWithButtons.vue"

const localVue = createLocalVue()
localVue.use(Vuex)

const mutations = {
  testMutation: jest.fn()
}

const store = new Vuex.Store({ mutations })

describe("ComponentWithButtons", () => {

  it("commits a mutation when a button is clicked", async () => {
    const wrapper = shallowMount(ComponentWithButtons, {
      store, localVue
    })

    wrapper.find(".commit").trigger("click")
    await wrapper.vm.$nextTick()

    expect(mutations.testMutation).toHaveBeenCalledWith(
      {},
      { msg: "Test Commit" }
    )
  })

})

注意测试被标记为 await   并调用了   nextTick 。

上面的测试中有很多代码 -- 尽管并没有什么让人兴奋的事情发生。我们创建了一个 localVue  并 use 了 Vuex,然后创建了一个 store,传入一个 Jest mock 函数 ( jest.fn() ) 代替   testMutation 。Vuex mutations 总是以两个参数的形式被调用:第一个参数是当前 state,第二个参数是 payload。因为我们并没有为 store 声明任何 state,我们预期它被调用时第一个参数会是一个空对象。第二个参数预期为   { msg: "Test Commit" } ,也就是硬编码在组件中的那样。

有好多样板代码要去写,但这是个验证组件行为正确性的恰当而有效的方式。另一种替代方法 mock store 需要的代码更少。让我们来看看如何以那种方式编写一个测试并断言 testAction   被 dispatch 了。

5.3 - 用一个 mock store 测试 action

让我们来看看代码,然后和前面的测试类比、对比一下。请记住,我们要验证:

正确的 action 被 dispatch 了

payload 是正常的

it("dispatches an action when a button is clicked", async () => {
  const mockStore = { dispatch: jest.fn() }
  const wrapper = shallowMount(ComponentWithButtons, {
    mocks: {
      $store: mockStore
    }
  })

  wrapper.find(".dispatch").trigger("click")
  await wrapper.vm.$nextTick()
  
  expect(mockStore.dispatch).toHaveBeenCalledWith(
    "testAction" , { msg: "Test Dispatch" })
})

这比前一个例子要紧凑多了。没有 localVue 、没有   Vuex   -- 不同于在前一个测试中我们用  testMutation: jest.fn()   mock 掉了   commit   后会触发的函数,这次我们实际上 mock 了   dispatch   函数本身。因为   $store.dispatch   只是一个普通的 JavaScript 函数,我们有能力做到这点。而后我们断言第一个参数是正确的 action 处理函数名   testAction 、第二个参数 payload 也正确。我们不关心实际发生的 -- 那可以被单独地测试。本次测试的目的就是简单地验证单击一个按钮会 dispatch 正确的带 payload 的 action。

使用真实的 store 或 mock store 全凭个人喜好。都是正确的。重要的事情是你在测试组件。

5.4 - 测试一个 Namespaced Action (或 Mutation)

第三个也是最终的例子展示了另一种测试一个 action 是否被以正确的参数 dispatch (或是 mutation 被 commit)的方式。这结合了以上讨论过的两项技术 -- 一个真实的 Vuex   store,和一个 mock 的   dispatch   方法。

it("dispatch a namespaced action when button is clicked", async () => {
  const store = new Vuex.Store()
  store.dispatch = jest.fn()

  const wrapper = shallowMount(ComponentWithButtons, {
    store, localVue
  })

  wrapper.find(".namespaced-dispatch").trigger("click")
  await wrapper.vm.$nextTick()

  expect(store.dispatch).toHaveBeenCalledWith(
    'namespaced/very/deeply/testAction',
    { msg: "Test Namespaced Dispatch" }
  )
})

根据我们感兴趣的模块,从创建一个 Vuex store 开始。我在测试内部声明了模块,但在真实 app 中,你可能需要引入组件依赖的模块。其后我们把 dispatch   方法替换为一个   jest.fn mock,并对它做了断言。


6. 总结

mutations   和   getters   都只是普通的 JavaScript 函数,它们可以、也应该,被区别于主 Vue 应用而单独地测试

当单独地测试 getters   时,你需要手动传入 state

如果一个 getter 使用了其他 getters,你应该用符合期望的返回结果 stub 掉后者。这将给我们对测试更细粒度的控制,并让你聚焦于测试中的 getter

测试一个 action 时,可以使用 Jest ES6 class mocks,并应该同时测试其成功和失败的情况

可以使用 createLocalVue   和真实 Vuex store 测试   $store.state   和   getters

可以使用 mocks   加载选项 mock 掉   $store.state   和   getters   等

可以使用 computed   加载选项以设置 Vuex getter 的期望值

可以直接 mock 掉 Vuex 的 API ( dispatch   和   commit )

可以通过一个 mock 的 dispatch   函数使用一个真实的 Vuex store

--End--

搜索关注公众号:fewelife


链接: https://www.fly63.com/article/detial/7064

测试工具比较:选Jest,不选Mocha

Jest的未来看起来非常令人激动!看到Jest推陈出新如此快速,我感觉它将很快成为整个React生态系统中大部分项目的首选工具。我建议,应该把测试迁移到Jest上去。

你需要了解的前端测试“金字塔”

如果您正在测试前端应用程序,则应该了解前端测试金字塔。在本文中,我们将看到前端测试金字塔是什么,以及如何使用它来创建全面的测试套件。

web网页性能测试工具都有哪些

作为前端开发,我们不仅需要满足产品需求功能的实现,同时也需要对自己做的网站进行安全、易用性、性能等方面的考虑。随着目前技术不断进步,web页面的性能测试工具也在不断完善,通过这些工具,我们可以客观的评价web网站的质量水平。

js单元测试工具-jest自动化测试

jest 是 facebook 开源的,用来进行单元测试的框架,可以测试 javascipt 和 react。jest 提供了非常方便的 API,可以对下面的场景方便的测试:一般函数、异步函数、测试的生命周期、react 测试

web测试要点、方法_web端测试大全总结

web测试大全,测试web网站有哪些点呢?主要包括:功能测试、兼容性测试、安全测试、输入框测试、用户权限测试等

前端性能测试工具整理简介_性能测试工具都有哪些?

前端性能测试工具都有哪些:Favicon、Open Graph、图片优化-压缩图像、CSS 优化-Autoprefixer、Purifycss、minify CSS、减少载入时间、GZIP、CDN、优化平台-Sentry、Google Tag Manager

不用写代码,也能做好接口测试

本文你将了解到:1、接口测试基本概念,包含什么是接口,什么是接口测试,为什么要做接口测试;2、接口测试用例设计,3、怎样不用写代码,也能快速的根据开发的API文档完成接口自动化测试脚本

Selenium打开浏览器加载慢的原因

在自动化元素定位操作中经常使用智能等待来加强定位的强壮性,主要就是因为WebDriver没有提供页面加载场景的方法;在使用JavaScript知识的突然心生灵感,可以使用JavaScript来配合验证页面加载,结果发现我真是井底之蛙。

power assert_更智能、优雅的全方位 assert 断言库

在写测试代码时,以往我们需要翻阅文档,学习各种 API 才能明白如何操作断言。而现在我们可以透过 power-assert 的 assert 方法来减轻调试压力。不仅如此,它还提供更加直观,具体的运行效果,帮助 DEBUG。写测试代码,其实可以很容易。

常用的web网站负载/压力/性能测试工具

在网站上线发布之前,我们除了必要的安全、功能测试外,往往还需要进行压力测试。通过模拟实际应用的软硬件环境及用户使用过程的系统负荷,长时间或超大负荷地运行测试软件。包括:Apache JMeter 、LoadRunner、NeoLoad等

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!