作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
米哈伊尔拥有物理学硕士学位. He’s run the gamut with Node.js, Go, JavaScript spa, React.js, Flux/Redux, RIOT.js, and AngularJS.
测试是构建健壮Node的重要组成部分.js application. 适当的测试可以很容易地克服开发人员可能指出的许多缺点 Node.js development solutions.
虽然许多开发人员关注单元测试的100%覆盖率, 重要的是,您编写的代码不是单独测试的. 集成和端到端测试通过一起测试应用程序的各个部分,为您提供了额外的信心. 这些部件可能自己工作得很好, but in a large system, 代码单元很少单独工作.
Node.js和MongoDB一起构成了最近最受欢迎的二人组之一. 如果你恰好是使用它们的许多人中的一员,那么你很幸运.
在本文中,您将学习如何轻松地为Node编写集成和端到端测试.在数据库的真实实例上运行的MongoDB应用程序,而不需要设置一个复杂的环境或复杂的设置/拆除代码.
您将看到mongo-unit包如何帮助在Node中进行集成和端到端测试.js. 以获取更全面的Node概述.js integration tests, see this article.
Typically, 用于集成或端到端测试, 您的脚本将需要连接到一个真正的专用数据库以进行测试. 这包括编写在每个测试用例/套件的开始和结束处运行的代码,以确保数据库处于干净的可预测状态.
这可能对某些项目很有效,但也有一些局限性:
On the other hand, 使用真实的数据库使测试环境尽可能接近生产环境. 这可以看作是这种方法的一个特殊优势.
使用真实的数据库进行测试似乎有一些挑战. 但是,使用真实数据库的优势太好了,无法传递. 我们如何应对挑战并保持优势?
重用来自另一个平台的好的解决方案并将其应用于Node.Js的世界可以是这里的路.
Java项目广泛使用DBUnit和内存数据库.g., H2) for this purpose.
DBUnit与JUnit (Java测试运行器)集成,并允许您定义每个测试/测试套件的数据库状态, etc. 它消除了上面讨论的约束:
从这些概念出发,我决定为Node做一些类似的东西.js and MongoDB: Mongo-unit.
Mongo-unit is a Node.可以使用NPM或Yarn安装. It runs MongoDB in-memory. 通过与Mocha很好地集成并提供一个简单的API来管理数据库状态,它使集成测试变得容易.
The library uses the mongodb-prebuilt NPM包,其中包含为流行操作系统预构建的MongoDB二进制文件. 这些MongoDB实例可以在内存模式下运行.
要将mongo-unit添加到你的项目中,你可以运行:
npm install -D mongo-unit
or
yarn add mongo-unit
And, that is it. 您甚至不需要在计算机上安装MongoDB就可以使用这个包.
假设您有一个简单的Node.Js应用程序来管理任务:
// service.js
Const mongoose = require('mongoose')
const mongoUrl = process.env.MONGO_URL || 'mongodb://localhost:27017/example'
mongoose.connect(mongoUrl)
const TaskSchema = new mongoose.Schema({
name: String,
started: Date,
completed: Boolean,
})
const Task = mongoose.model('tasks', TaskSchema)
module.exports = {
getTasks: () => Task.find(),
addTask: data => new Task(data).save(),
deleteTask: taskId => Task.findByIdAndRemove(taskId)
}
MongoDB连接URL在这里不是硬编码的. 与大多数web应用程序后端一样,我们从环境变量中获取它. 这将允许我们在测试期间将其替换为任何URL.
Const express = require('express')
const bodyParser = require('body-parser')
const service = require('./service')
const app = express()
app.use(bodyParser.json())
app.use(express.静态的(“$ {__dirname} /静态”))
app.get('/example', (req, res) => {
service.getTasks().then(tasks => res.json(tasks))
})
app.post('/example', (req, res) => {
service.addTask(req.body).then(data => res.json(data))
})
app.delete('/example/:taskId', (req, res) => {
service.deleteTask(req.params.taskId).then(data => res.json(data))
})
app.listen(3000, () => console.log('started on port 3000'))
这是一个具有用户界面的示例应用程序的代码片段. 为简洁起见,省略了UI的代码. 您可以查看完整的示例 on GitHub.
让Mocha运行针对mongo-unit的集成测试, 我们需要在将应用程序代码加载到Node之前运行mongo-unit数据库实例.js context. To do this, we can use the mocha --require
参数和Mocha-prepare库, 哪一个允许您在require脚本中执行异步操作.
// it-helper.js
Const prepare = require('mocha-prepare')
const mongoUnit = require('mongo-unit')
prepare(done => mongoUnit.start()
.then(testMongoUrl => {
process.env.MONGO_URL = testMongoUrl
done()
}))
第一步是将测试添加到测试数据库(testData.json
):
{
"tasks": [
{
"name": "test",
“开始”:“2017 - 08 - 28 - t16:07:38.268Z",
"completed": false
}
]
}
下一步是添加测试本身:
Const expect = require('chai').expect
Const mongoose = require('mongoose')
const mongoUnit = require('../index')
const service = require('./app/service')
const testMongoUrl = process.env.MONGO_URL
describe('service', () => {
const testData = require('./fixtures/testData.json')
beforeEach(() => mongoUnit.initDb (testMongoUrl testData))
afterEach(() => mongoUnit.drop())
it('should find all tasks', () => {
return service.getTasks()
.then(tasks => {
expect(tasks.length).to.equal(1)
expect(tasks[0].name).to.equal('test')
})
})
it('should create new task', () => {
return service.addTask({name: 'next', completed: false})
.then(task => {
expect(task.name).to.equal('next')
expect(task.completed).to.equal(false)
})
.then(() => service.getTasks())
.then(tasks => {
expect(tasks.length).to.equal(2)
expect(tasks[1].name).to.equal('next')
})
})
it('should remove task', () => {
return service.getTasks()
.then(tasks => tasks[0]._id)
.then(taskId => service.deleteTask(taskId))
.then(() => service.getTasks())
.then(tasks => {
expect(tasks.length).to.equal(0)
})
})
})
And, voila!
请注意,这里处理设置和删除的代码只有几行.
正如您所看到的,使用mongo-unit库编写集成测试非常容易. 我们不模拟MongoDB本身,我们可以使用相同的Mongoose模型. 我们完全控制了数据库数据,并且在测试性能上没有损失太多 fake MongoDB is running in memory.
这也允许我们将最佳单元测试实践应用于集成测试:
作为奖励,我们甚至可以在mongo-unit上运行应用程序本身. 它允许我们针对模拟数据库对应用程序进行端到端测试.
对于端到端测试,我们将使用 Selenium WebDriver and Hermione E2E test runner.
首先,我们将引导驱动程序和测试运行程序:
const mongoUnit = require('mongo-unit')
Const selenium = require('selenium-standalone')
const Hermione = require(' Hermione ')
新赫敏()./e2e/hermione.conf.js') //hermione config
seleniumInstall() //确保安装了selenium
.然后(seleniumStart) //启动selenium web驱动程序
.then(mongoUnit.start) // start mongo unit
.then(testMongoUrl => {
process.env.MONGO_URL = testMongoUrl //存储mongo的url
})
.then(() => {
require('./index.js') //start application
})
.然后(delay(1000)) //等待一秒钟,直到应用程序启动
.then(() => hermione.run(", heroneopts)) //运行heronee2e测试
.then(() => process.exit(0))
.catch(() => process.exit(1))
我们还需要一些辅助函数(为了简洁,删除了错误处理):
function seleniumInstall() {
return new Promise(resolve => selenium.install({}, resolve))
}
function seleniumStart() {
return new Promise(resolve => selenium.start(resolve))
}
function delay(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout))
}
用一些数据填充数据库,并在测试完成后清理数据库, we can run our first tests:
Const expect = require('chai').expect
const co = require('co')
const mongoUnit = require('../index')
const testMongoUrl = process.env.MONGO_URL
const DATA = require('./fixtures/testData.json')
const ui = {
task: '.task',
remove: '.task .remove',
name: '#name',
date: '#date',
addTask: '#addTask'
}
describe('Tasks', () => {
beforeEach(function () {
return mongoUnit.initDb(testMongoUrl, DATA)
.then(() => this.browser.url('http://localhost:3000'))
})
afterEach(() => mongoUnit.dropDb(testMongoUrl))
它('应该显示任务列表',function () {
const browser = this.browser
return co(function* () {
const tasks = yield browser.elements(ui.task)
expect(tasks.length, 1)
})
})
It ('should create task', function () {
const browser = this.browser
return co(function* () {
yield browser.element(ui.name).setValue('test')
yield browser.element(ui.addTask).click()
const tasks = yield browser.elements(ui.task)
expect(tasks.length, 2)
})
})
It ('should remove task', function () {
const browser = this.browser
return co(function* () {
yield browser.element(ui.remove).click()
const tasks = yield browser.elements(ui.task)
expect(tasks.length, 0)
})
})
})
正如您所看到的,端到端测试看起来与集成测试非常相似.
集成和端到端测试对于任何大型应用程序都很重要. Node.特别是Js应用程序,可以从自动化测试中获益良多. With mongo-unit, 您可以编写集成和端到端测试,而不必担心这些测试带来的所有挑战.
You can find complete examples 如何在GitHub上使用mongo-unit.
集成测试是一种自动化测试,用于验证系统的多个组件在各种情况下是否正确工作.
E2E是端到端(end- end)的缩写,通常用于端到端测试的上下文中.
下诺夫哥罗德,下诺夫哥罗德州,俄罗斯
Member since July 6, 2015
米哈伊尔拥有物理学硕士学位. He’s run the gamut with Node.js, Go, JavaScript spa, React.js, Flux/Redux, RIOT.js, and AngularJS.
世界级的文章,每周发一次.
世界级的文章,每周发一次.
Join the Toptal® community.