authors are vetted experts in their fields and write on topics in which they have demonstrated experience. All of our content is peer reviewed and validated by Toptal experts in the same field.
测试是构建健壮Node的重要组成部分.js应用程序. Proper tests can easily overcome a lot of shortcomings that developers may point out about Node.Js开发方案.
虽然许多开发人员关注单元测试的100%覆盖率, it is important that the code you write is not just tested in isolation. Integration and end-to-end tests give you that extra confidence by testing parts of your application together. 这些部件可能自己工作得很好, 但是在一个大系统中, 代码单元很少单独工作.
Node.js和MongoDB together form one of the most popular duos of recent times. 如果你恰好是使用它们的许多人中的一员,那么你很幸运.
在本文中, you will learn how to write integration and end-to-end tests easily for your Node.js和MongoDB application that run on real instances of the database all without needing to set up an elaborate environment or complicated setup/teardown code.
You will see how the mongo-unit package helps with integration and end-to-end testing in Node.js. 以获取更全面的Node概述.Js集成测试,参见 这篇文章.
通常, 用于集成或端到端测试, your scripts will need to connect to a real dedicated database for testing purposes. This involves writing code that runs at the beginning and end of every test case/suite to ensure that the database is in a clean predictable state.
这可能对某些项目很有效,但也有一些局限性:
另一方面, using a real database makes the test environment as close to production as possible. 这可以看作是这种方法的一个特殊优势.
使用真实的数据库进行测试似乎有一些挑战. 但是,使用真实数据库的优势太好了,无法传递. 我们如何应对挑战并保持优势?
Reusing a good solution from another platform and applying it to the Node.Js的世界可以是这里的路.
Java项目广泛使用DBUnit和内存数据库.g.(H2)用于此目的.
DBUnit is integrated with JUnit (the Java test runner) and lets you define the database state for each test/testing suite, etc. 它消除了上面讨论的约束:
Taking from these concepts, I decided to make something similar for Node.. js和MongoDB: Mongo-unit.
Mongo-unit是一个Node.可以使用NPM或Yarn安装. 它在内存中运行MongoDB. It makes integration tests easy by integrating well with Mocha and providing a simple API to manage the database state.
图书馆使用 mongodb-prebuilt NPM package, which contains prebuilt MongoDB binaries for the popular operating systems. 这些MongoDB实例可以在内存模式下运行.
要将mongo-unit添加到你的项目中,你可以运行:
npm install -D mongo-unit
or
纱线添加蒙古单位
就是这样. You do not even need MongoDB installed on your computer to use this package.
假设您有一个简单的Node.Js应用程序来管理任务:
/ /服务.js
Const 猫鼬 = 要求(“猫鼬')
const mongoUrl =进程.env.MONGO_URL || 'mongodb://localhost:27017/example'
猫鼬.连接(mongoUrl)
const TaskSchema = new 猫鼬.模式({
名称:字符串,
:开始日期,
完成:布尔,
})
const任务=猫鼬.模型(“任务”,TaskSchema)
module.出口= {
getTasks: () => Task.find(),
addTask: data => new Task(data).save(),
deleteTask: taskId => Task.findByIdAndRemove (taskId)
}
MongoDB连接URL在这里不是硬编码的. As with most web application back-ends, we are taking it from the environment variable. 这将允许我们在测试期间将其替换为任何URL.
Const express = 要求(“express')
const bodyParser = 要求(“body-parser')
Const service = 要求(“./服务”)
Const app = express()
app.使用(bodyParser.json())
app.使用(表达.静态的(“$ {__dirname} /静态”))
app.get('/example', (req, res) => {
service.getTasks ().then(tasks => res.json(任务))
})
app.post('/example', (req, res) => {
service.addTask(要求.body).then(data => res.json(数据))
})
app.delete('/example/:taskId', (req, res) => {
service.deleteTask(要求.params.taskId).then(data => res.json(数据))
})
app.listen(3000, () => console.日志('在端口3000启动'))
这是一个具有用户界面的示例应用程序的代码片段. 为简洁起见,省略了UI的代码. 您可以查看完整的示例 GitHub上.
让Mocha运行针对mongo-unit的集成测试, we need to run the mongo-unit database instance before the application code is loaded in the Node.js上下文. 要做到这一点,我们可以使用 摩卡,需要
参数和Mocha-prepare库, which allows you to perform asynchronous operations in the require scripts.
/ / it-helper.js
Const prepare = 要求(“mocha-prepare')
const monounit = 要求(“mongo-unit')
prepare(done => mongoUnit.start()
.then(testMongoUrl => {
process.env.MONGO_URL = testmongodb
done()
}))
第一步是将测试添加到测试数据库(testData.json
):
{
“任务”:[
{
“名称”:“测试”,
“开始”:“2017 - 08 - 28 - t16:07:38.268Z",
“完成”:假的
}
]
}
下一步是添加测试本身:
Const expect = 要求(“chai').expect
Const 猫鼬 = 要求(“猫鼬')
const monounit = 要求(“../指数”)
Const service = 要求(“./应用程序/服务”)
const testMongoUrl =进程.env.MONGO_URL
describe('service', () => {
const testData = 要求(“./夹具/ testData.json')
beforeEach(() => mongoUnit.initDb (testMongoUrl testData))
afterEach(() => mongoUnit.drop())
it('should find all tasks', () => {
返回服务.getTasks ()
.then(tasks => {
期望(任务.length).to.= (1)
期望(任务[0].name).to.平等(测试)
})
})
it('should create new task', () => {
返回服务.addTask({name: 'next', completed: false})
.then(task => {
期望(任务.name).to.平等(下)
期望(任务.完成).to.平等的(错误的)
})
.then(() => service.getTasks ())
.then(tasks => {
期望(任务.length).to.等于(2)
期望(任务[1].name).to.平等(下)
})
})
it('should remove task', () => {
返回服务.getTasks ()
.then(tasks => tasks[0]._id)
.then(taskId => service.deleteTask (taskId))
.then(() => service.getTasks ())
.then(tasks => {
期望(任务.length).to.equal(0)
})
})
})
而且,瞧!
Notice how there are just a couple of lines of code dealing with setup and teardown.
As you can see, it’s very easy to write integration tests using the mongo-unit library. We do not mock MongoDB itself, and we can use the same Mongoose models. We have full control of the database data and do not lose much on test performances since the fake MongoDB在内存中运行.
This also allows us to apply the best unit testing practices for integration tests:
作为奖励,我们甚至可以在mongo-unit上运行应用程序本身. It allows us to make end-to-end tests for our application against a mocked database.
对于端到端测试,我们将使用 硒WebDriver and 赫敏E2E测试员.
首先,我们将引导驱动程序和测试运行程序:
const monounit = 要求(“mongo-unit')
Const selenium = 要求(“selenium-standalone')
const Hermione = 要求(“ Hermione ')
新赫敏()./ e2e赫敏.conf.Js’)//赫敏配置
seleniumInstall() //确保安装了selenium
.然后(seleniumStart) //启动selenium web驱动程序
.然后(mongoUnit.Start) //启动mongo单元
.then(testMongoUrl => {
process.env.MONGO_URL = testmongodb //存储mongo的url
})
.then(() => {
要求(“./index.Js’)//启动应用程序
})
.然后(delay(1000)) //等待一秒钟,直到应用程序启动
.then(() => hermione.run(", heroneopts)) //运行heronee2e测试
.then(() => process.退出(0))
.catch(() => process.退出(1))
We will also need some helper functions (error handling removed for brevity):
函数seleniumInstall() {
return new Promise(resolve => selenium.解决安装({}))
}
函数seleniumStart() {
return new Promise(resolve => selenium.开始(解决)
}
函数delay(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout))
}
After filling the database with some data and cleaning it once the tests are done, 我们可以运行第一个测试:
Const expect = 要求(“chai').expect
Const co = 要求(“co')
const monounit = 要求(“../指数”)
const testMongoUrl =进程.env.MONGO_URL
const DATA = 要求(“./夹具/ testData.json')
Const UI = {
task: '.task',
删除:“.task .remove',
名称:“#名称”,
日期:“#日期”,
addTask:“# addTask”
}
describe('Tasks', () => {
beforeEach(function () {
返回mongoUnit.initDb (testMongoUrl、数据)
.then(() => this.browser.url (http://localhost: 3000))
})
afterEach(() => mongoUnit.dropDb (testMongoUrl))
它('应该显示任务列表',function () {
Const browser = this.browser
返回co(function* () {
Const任务= yield浏览器.(ui元素.task)
期望(任务.长度,1)
})
})
It ('should create task', function () {
Const browser = this.browser
返回co(function* () {
收益率的浏览器.ui元素(.name).setValue(测试)
收益率的浏览器.ui元素(.addTask).click()
Const任务= yield浏览器.(ui元素.task)
期望(任务.长度,2)
})
})
It ('should remove task', function () {
Const browser = this.browser
返回co(function* () {
收益率的浏览器.ui元素(.remove).click()
Const任务= yield浏览器.(ui元素.task)
期望(任务.长度,0)
})
})
})
As you can see, the end-to-end tests look very similar to the integration tests.
Integration and end-to-end testing are important for any large-scale application. Node.js应用程序s, in particular, can benefit tremendously from automated testing. 与mongo-unit, you can write integration and end-to-end testing without worrying about all the challenges that come with such tests.
你可以找到 完整的例子 如何在GitHub上使用mongo-unit.
An integration test is an automated test that is used to verify if multiple components of a system work correctly for various cases.
E2E is short for end-to-end, and is generally used in the context of end-to-end testing.
下诺夫哥罗德,下诺夫哥罗德州,俄罗斯
2015年7月6日加入
米哈伊尔拥有物理学硕士学位. 他和诺德关系很好.js, Go, JavaScript spa, React.. js, Flux/Redux, RIOT.js和AngularJS.
世界级的文章,每周发一次.
世界级的文章,每周发一次.