当使用测试驱动开发,或者在开发中需要充分引入测试的时候,不仅仅需要重视小粒度的测试,还需要重视整体业务过程的测试,这往往需要更复杂的测试手段,比如对REST API的测试,以及多个API调用组成的集成测试。本文简单总结一下与测试有关的一些技术。本文以Node.js为例进行说明。
测量工具
测试首先要确保覆盖率,包括代码覆盖率、分支条件覆盖率和函数覆盖率。尽可能做到100%覆盖。要做到这一点,需要有工具进行支持。在Node.js中,可以选择使用nyc。进行测试后,会生成测试报告,根据测试报告,可以发现未被覆盖的代码,进而完善测试。
内存数据库
数据库是应用软件离不开的支撑环境,在测试时,我们不可能连接真正的数据库,但却需要对涉及数据库的功能进行测试,最好的办法是使用功能完全一致的内存数据库。如果使用MongoDB,可以使用针对MongoDB的内存数据库mongodb-memory-server。
在使用mongodb-memory-server进行测试时,可以使用process.env传递数据库的连接串,然后在需要的地方,使用MongoClient初始化连接。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const {MongoMemoryServer} = require('mongodb-memory-server') var assert = require('assert'); var MongoClient = require('mongodb').MongoClient; describe('mongoUserCenter', function () { let mongoServer; before(async function () { mongoServer = await MongoMemoryServer.create(); const mongoUri = mongoServer.getUri(); process.env.mongo_url=mongoUri process.env.mongo_db="testdb" }) after(async () => { await mongoServer.stop(); });
})
|
在单元测试或者cucumber.js支持的行为驱动测试中,可以在测试开始前准备测试数据,测试完成后删除数据,这样确保每次测试的一致性。下面的代码在所有测试开始时导入必要的数据,在每次测试开始时,导入单个测试需要的数据,测试完成后删除,整体测试完成后,停止数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| BeforeAll(async function () { mongoServer = await MongoMemoryServer.create(); mongoUri = mongoServer.getUri(); const collections = [ "AUTH_USER_TB", "AUTH_ROLE_USER_TB"] var mongodb = await MongoClient.connect(mongoUri); var dbase = mongodb.db("testdb"); for (var i = 0; i < collections.length; i++) { const collectionName = collections[i]//"YJS_XMGL_QDLH_tb" const data = require('../../testData/' + collectionName + '.json') const rows = data.rows var collection = dbase.collection(collectionName); const result = await collection.insertMany(rows) } await mongodb.close() process.env.mongo_url = mongoUri process.env.mongo_db = "testdb"
app = require('../../appmodule')
})
Before(async function () { var mongodb = await MongoClient.connect(mongoUri); var dbase = mongodb.db("testdb"); const collectionName = "YJS_XMGL_QDLH_tb" const data = require('../../testData/' + collectionName + '.json') const rows = data.rows var collection = dbase.collection(collectionName); const result = await collection.insertMany(rows) await mongodb.close() }) After(async function () { ////console.log("After") var mongodb = await MongoClient.connect(mongoUri); var dbase = mongodb.db("testdb"); var collection = dbase.collection('YJS_XMGL_QDLH_tb') await collection.deleteMany({}) var vcollection = dbase.collection('verifications') await vcollection.deleteMany({}) await mongodb.close() })
AfterAll(async function () { await mongoServer.stop();
})
|
RESTful API 测试框架
我们需要对RESTful API进行测试,希望不启动服务器,与上一节所说的内存数据库一起使用,可以完整测试整个应用。我们需要引入相应的框架,在node.js中可以使用supertest。
我们对app.js进行改造,将路由定义与侦听部分分开,路由定义部分作为模块导出:
1 2 3 4 5 6 7 8 9
| app.use('/api',Routes) //const port = 3020;
/* app.listen(port, () => { //console.log(`Server listening on port ${port}`); }); */ module.exports=app
|
在侦听部分使用这个模块:
1 2 3 4 5 6
| const port = 3020; const app=require('./appmodule') app.listen(port, () => { console.log(`Server listening on port ${port}`); });
|
这样,模块部分可以使用supertest框架进行测试:
1 2 3 4 5 6 7 8 9
| it('查询项目', async function () { const response = await request(app) .get('/verificationapi/getNoVerificationProjects') .auth('jib678.qdlh', 'wangrk208.qdlh') .set('Accept', 'application/json'); const projects = JSON.parse(response.text) assert.equal(response.status, 200); assert.equal(projects.length > 0, true); });
|
使用上面这些技术进行组合,可以完备地测试整个应用。