• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

测试Node.js API

介绍

测试很重要,它们为您的应用程序api提供了保障作为初学者,可能会忘记编写涵盖您正在构建的重要部分的测试的需要。然而,当您作为开发人员取得进步时,您会遇到它。

在之前的教程中,您学习了如何使用 node.js 构建 API如果你还没有经历过,我建议你在继续之前这样做。在本教程中,您将为使用 Node.js 和 Express 构建的 API 编写测试。在本教程结束时,您将了解 Node.js 中的测试工作原理,并且您将能够构建功能性和经过测试的 API。

测试工具

您将使用 Mocha、Expect 和 Supertest。

Mocha是一个javascript测试框架,它使异步测试变得简单而有趣。Mocha 有很多很棒的功能,可以在网站上找到。您将使用其中的一小部分。

Expect是一个断言库,可让您轻松做出更好的断言。你会看到它是如何工作的。Supertest为测试 HTTP 提供了高级抽象。这是必要的,因为您将测试 API。

废话不多说,是时候写一些代码了。

项目设置

我已经为你设置了一个待办事项列表项目。模型、配置文件和 app.js 的一部分已经为您完成。转到 GitHub 并克隆存储库或者您可以简单地执行以下操作:

git clone https://github.com/izuchukwu1/node-todo-api.git

你的 package.json 应该是这样的。

#package.json

{
  "name": "node-todo-api",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": {
    "start": "node server/server.js",
    "test": "export NODE_ENV=test || SET \"NODE_ENV=test\" && mocha server/**/*.test.js",
    "test-watch": "nodemon --exec 'npm test'"
  },
  "engines": {
    "node": "8.0.0"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.17.2",
    "express": "^4.15.3",
    "lodash": "^4.17.4",
    "mongodb": "^2.2.29",
    "mongoose": "^4.11.1"
  },
  "devDependencies": {
    "expect": "^1.20.2",
    "mocha": "^3.4.2",
    "nodemon": "^1.11.0",
    "supertest": "^3.0.0"
  }
}

现在运行命令来安装依赖项。

npm install

发布请求测试

对于您的测试,创建一个名为test的新文件夹;该文件夹应该在您的服务器目录中。现在创建一个新文件,您将在其中编写测试。将文件命名为server.test.js

在此文件中,首先需要您安装的模块。您还需要要求您的服务器文件和模型。

#server/test/server.test.jsconst expect = require('expect')
const request = require('supertest')
const {ObjectId} = require('mongodb')

const {app} = require('./../server')
const {Todo} = require('./../models/todo')

您需要有一些将在测试期间使用的待办事项。但是每次运行测试套件时,这些待办事项都会从测试数据库中删除。为了解决这个问题,像这样创建两个测试。

#server/test/server.test.js

const todos = [{
  _id: new ObjectId(),
  text: "First test todo"
}, {
  _id: new ObjectId(),
  text: "Second test todo",
  completed: true,
  completedAt: 333
}]

beforeEach((done) => {
  Todo.remove({}).then(() => {
    return Todo.insertMany(todos)
  }).then(() => done())
})

before 块清理你的 Todo 数据库,然后插入上面设置的 to-dos。这可确保您的数据库中有稳定数量的条目,因此您的测试不会遇到问题。

完成后,您可以为post请求编写测试 。对于您的POST请求,您将编写两个测试。第一个将请求有效的待办事项并成功。第二个将使用无效的正文发出请求,这不应创建新的待办事项。

这是测试的样子。

#server/test/server.test.js

describe('POST /todos', () => { // 1
  it('should create a new todo', (done) => {
    let text = 'Test todo text' // 2

    request(app) // 3
      .post('/todos')
      .send({text})
      .expect(200)
      .expect((res) => {
        expect(res.body.text).toBe(text)
      })
      .end((err, res) => { // 4
        if (err) {
          return done(err)
        }

        Todo.find({text}).then((todos) => { // 5
          expect(todos.length).toBe(1)
          expect(todos[0].text).toBe(text)
          done()
        }).catch((e) => done(e))
      })
  })

  it('should not create todo with invalid body data', (done) => { // 6

    request(app) // 7
      .post('/todos')
      .send({})
      .expect(400)
      .end((err, res) => {
        if (err) {
          return done(err)
        }

        Todo.find().then((todos) => { // 8
          expect(todos.length).toBe(2)
          done()
        }).catch((e) => done(e))
      })
  })
})

使用以下命令运行测试:

npm run test

它应该失败。这是正在发生的事情:

  1. 描述测试。

  2. 创建一个新的待办事项并将其保存为文本值。

  3. 您向 API 的/todos路径发出 POST 请求,将您创建的待办事项作为请求的主体发送。您希望请求的状态代码为200,待办事项的正文等于 的值text

  4. 如果有任何错误,则返回错误,这将导致请求结束。因此下一个代码块将不会运行。如果没有遇到错误,则流程继续。

  5. 向数据库发出请求以查找创建的待办事项。您希望数据库中待办事项的长度为 1,待办事项的文本等于文本的值。

  6. 这是使用无效身体数据进行的测试。

  7. 向/todos路径发出POST请求。这一次,您发送的请求没有正文。您预计会收到400 个请求。无需检查正文,因为您没有发送任何内容。如果遇到错误,它会被返回并且代码停止运行。

  8. 如果没有遇到错误,则向数据库发出请求以检查待办事项的长度。我们预计数据库将只包含 2 个,它们是一开始创建的待办事项。

要通过此测试,请转到您的server.js文件并放入 POST 请求所需的代码。

#server/server.js

app.post('/todos', (req, res) => {
  let todo = new Todo({
    text: req.body.text
  })

  todo.save().then((doc) => {
    res.send(doc)
  }, (e) => {
    res.status(400).send(e)
  })
})

GET 请求测试

这很简单——测试应该返回数据库中可用的待办事项的长度。正如你已经知道的,待办事项的长度应该是 2。为什么?你猜对了。在测试套件开始时,您创建了一个beforeEach块来清理您的数据库并在每次运行测试套件时插入新的待办事项。

为了测试获取所有待办事项的请求是否有效,这里是它的代码。

#server/test/server.test.js

describe('GET /todos', () => {
  it('should get all todos', (done) => {
    request(app)
      .get('/todos')
      .expect(200)
      .expect((res) => {
        expect(res.body.todos.length).toBe(2)
      })
      .end(done)
  })
})

在上面,您正在向/todos路径发出GET请求 。这一次,您没有将任何内容作为请求的主体传递,因为它是一个GET请求。您希望收到状态码为200的响应。然后您期望待办事项的长度为 2。

当你运行测试时,你应该得到一个错误。尝试让错误自行传递。

我敢打赌你一定能做到。这是使测试通过的代码;将其与您的解决方案进行比较。

#server/server.js

app.get('/todos', (req, res) => {
  Todo.find().then((todos) => {
    res.send({todos})
  }, (e) => {
    res.status(400).send(e)
  })
})

当对/todos路径发出GET请求 时,您希望找到 Todo 集合中的每个待办事项并将它们作为待办事项返回。将此添加到server.js会导致测试通过。

接下来,您将为检索单个待办事项而发出的GET请求编写三个测试。第一个应该检索并返回待办事项。在未找到待办事项的情况下,第二个和第三个应该返回404错误。

打开你的server.test.js并使用第一个测试用例创建一个新的 describe 块。

#server/server.test.js

describe('GET /todos/:id', () => {
  it('should return todo doc', (done) => {
    request(app)
      .get(`/todos/${todos[0]._id.toHexString()}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.todo.text).toBe(todos[0].text)
      })
      .end(done)
  })

此测试发出GET请求以检索数据库中可用的第一个待办事项。您期望获得200状态代码,然后检查待办事项的文本值是否与创建的相同。

下一个测试看起来像这样。

  it('should return 404 if todo is not found', (done) => {
    let _id = new ObjectId('5967989ee978311656e93a59')
    request(app)
      .get(`/todos/${todos/_id.toHexString()}`)
      .expect(404)
      .end(done)
  })

在这里,您正在使用与保存在数据库中的任何待办事项的 ID 不对应的 ID 查找待办事项。测试期望此请求返回404错误。

最后一个测试和第一个一样,但有一点不同;这是它的外观。

  it('should return 404 for non-object ids', (done) => {
    let hexId = '5967989ee978311656e93a5312'
    request(app)
      .get(`/todos/${todos/hexId}`)
      .expect(404)
      .end(done)
  })
})

在这里,您创建了一个无效的ObjectId并尝试查询数据库以获取与创建的待办事项匹配的内容ObjectId测试期望请求返回404错误。 

当您运行测试时,它们都应该失败。要让它们通过,请将以下代码添加到您的server.js文件中。

#server/server.js

app.get('/todos/:id', (req, res) => {
  let id = req.params.id // 1
   
  if (!ObjectId.isValid(id)) { // 2
    return res.status(404).send('ID is not valid')
  }

  Todo.findById(id).then((todo) => {
    if (!todo) { // 3
      return res.status(404).send()
    }
    res.send({todo}) //4
  }).catch((e) => {
    res.status(400).send()
  })
})
  1. 从参数中获取待办事项的 ID。

  2. 检查***是否有效。如果 ID 无效,则会发送一个错误说明。

  3. findById如果 ID 有效,请尝试使用该方法查找与该 ID 匹配的待办事项。如果没有找到具有该 ID 的待办事项,则会发送404错误。

  4. 如果找到待办事项,则发送待办事项。然后你捕获任何发生的错误并发送它。

再次运行测试命令,它应该可以通过。

删除请求测试

对您的DELETE请求的测试将有点像您对 GET 请求的测试。

首先,您要测试是否删除了待办事项。

#server/test/server.test.js

describe('DELETE /todos/:id', () => {
  it('should delete a todo', (done) => {
    let hexId = todos[0]._id.toHexString() // 1
    request(app)
      .delete(`/todos/${hexId}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.todo._id).toBe(hexId)
      })
      .end((err, res) => { // 2
        if (err) {
          return done(err)
        }
      })

      Todo.findById(hexId).then((todo) => { // 3
        expect(todo.hexId).toNotExist()
        done()
      }).catch((e) => done(e))
  })

这是上面发生的事情:

  1. 您将待办事项的 id 设置为名为 的变量hexId接下来,使用 ID 对待办事项的路径发出DELETE请求。您期望获得200响应,并且获得的待办事项与 的值相匹配hexId

  2. 如果遇到任何错误,则将其返回。

  3. 如果没有错误,测试会进一步使用保存为 值的 ID 查询您的数据库hexId由于先前已发送DELETE请求,因此测试预计不存在与该 ID 匹配的待办事项。

接下来,您要测试当请求删除不存在的待办事项时,响应包含404错误。拥有这一点很重要,因为不可能两次删除待办事项。这是测试的外观。

#server/test/server.test.js

  it('should return 404 if todo is not found', (done) => {
    let hexId = new ObjectId().toHexString()
    request(app)
      .delete(`/todos/${todos/hexId}`)
      .expect(404)
      .end(done)
  })

这会为数据库中不存在的待办事项创建一个 ID。然后发出DELETE请求以删除待办事项。由于待办事项不存在,测试预计会返回404错误。

您想测试使用无效 ID的DELETE是否返回404错误,如下所示。

#server/test/server.test.js

  it('should return 404 for non-object ids', (done) => {
    request(app)
      .delete('/todos/123abc')
      .expect(404)
      .end(done)
  })
})

为了让测试通过,打开你的 server.js 并删除它。

#server/server.js

app.delete('/todos/:id', (req, res) => {
  let id = req.params.id

  if (!ObjectId.isValid(id)) {
    return res.status(404).send()
  }

  Todo.findByIdAndRemove(id).then((todo) => {
    if (!todo) {
      return res.status(404).send()
    }
    res.send({todo})
  }).catch((e) => {
    res.status(400).send()
  })
})

运行命令进行测试:

npm run test

你的测试应该通过了。

结论

至此,您现在知道如何在使用 Node.js 构建 API 时设置测试套件。您已经使用 Mocha、Expect 和 Supertest 来测试 API。这样做的一个好处是您在构建 API 时不需要总是启动 Postman。通过您的测试,您可以了解发生了什么问题。


文章目录
  • 介绍
  • 测试工具
  • 项目设置
  • 发布请求测试
  • GET 请求测试
  • 删除请求测试
  • 结论