Setup of integrated testing environment
Environment Preparation
To set up a Koa2 integration testing environment, first ensure the basic toolchain is in place. It is recommended to use an LTS version of Node.js (e.g., 16.x or 18.x), with npm automatically installed alongside Node.js. Install Yarn globally as the package management tool:
npm install -g yarn
Initialize the project using Yarn to create the basic structure:
mkdir koa2-integration-test
cd koa2-integration-test
yarn init -y
Key dependencies need to be installed step by step. First, install the Koa2 core and commonly used middleware:
yarn add koa @koa/router koa-bodyparser
Testing-related dependencies should be separated into devDependencies and production dependencies. Install the testing framework and assertion library using the following command:
yarn add -D mocha chai supertest nyc
Test Framework Configuration
Mocha, as the test runner, requires a configuration file. Create .mocharc.json
in the project root directory:
{
"require": ["esm"],
"extension": ["js"],
"timeout": 5000,
"recursive": true,
"exit": true
}
The test directory structure is recommended to be divided by functional modules:
test/
├── integration/
│ ├── user.test.js
│ └── product.test.js
├── fixtures/
└── utils/
Add test scripts to package.json
:
{
"scripts": {
"test": "NODE_ENV=test mocha",
"test:cov": "nyc --reporter=text mocha"
}
}
Application Instance Encapsulation
Testing requires an independent Koa application instance. Create test/bootstrap.js
:
const Koa = require('koa')
const app = new Koa()
// Load middleware
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
// Dynamic route loading
const fs = require('fs')
const path = require('path')
const routerFiles = fs.readdirSync(path.join(__dirname, '../routes'))
routerFiles.forEach(file => {
const router = require(`../routes/${file}`)
app.use(router.routes())
})
module.exports = app
Database Isolation Handling
Integration testing requires an isolated test database. Use environment variables to switch configurations:
// config/database.js
const isTest = process.env.NODE_ENV === 'test'
module.exports = {
host: isTest ? 'localhost' : 'prod.db.example.com',
name: isTest ? 'test_db' : 'production_db'
}
Example helper function for initializing the database before testing:
// test/utils/db.js
const { MongoClient } = require('mongodb')
async function resetTestDB() {
const client = new MongoClient('mongodb://localhost:27017')
await client.connect()
const db = client.db('test_db')
// Clear collections
const collections = await db.collections()
await Promise.all(collections.map(col => col.deleteMany({})))
// Insert base data
await db.collection('users').insertMany([
{ name: 'test1', role: 'admin' },
{ name: 'test2', role: 'user' }
])
await client.close()
}
HTTP Test Case Writing
Use supertest
to write API test cases. Example user module test:
// test/integration/user.test.js
const request = require('supertest')
const app = require('../../test/bootstrap')
const { expect } = require('chai')
describe('User API', () => {
before(async () => {
await require('../utils/db').resetTestDB()
})
describe('GET /users', () => {
it('should return all users', async () => {
const res = await request(app.callback())
.get('/users')
.expect(200)
expect(res.body).to.have.lengthOf(2)
expect(res.body[0]).to.have.property('name', 'test1')
})
})
describe('POST /users', () => {
it('should create new user', async () => {
const mockUser = { name: 'new_user', email: 'test@example.com' }
const res = await request(app.callback())
.post('/users')
.send(mockUser)
.expect(201)
expect(res.body).to.have.property('_id')
expect(res.body.name).to.equal(mockUser.name)
})
})
})
Test Coverage Integration
Istanbul's nyc
tool requires a .nycrc
configuration file:
{
"all": true,
"include": ["routes/**/*.js", "controllers/**/*.js"],
"exclude": ["**/*.spec.js", "**/node_modules/**"],
"reporter": ["lcov", "text"],
"check-coverage": true,
"branches": 80,
"lines": 80,
"functions": 80,
"statements": 80
}
Generate HTML reports in CI environments:
nyc --reporter=html mocha
Continuous Integration Configuration
GitHub Actions configuration example (.github/workflows/test.yml
):
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
mongodb:
image: mongo:4.4
ports: ['27017:27017']
options: --health-cmd "mongo --eval 'db.stats()'" --health-interval 10s
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
- run: yarn install
- run: yarn test:cov
- name: Upload coverage
uses: codecov/codecov-action@v1
Test Data Factory
Use factory-girl
to create test data:
// test/factories/user.js
const factory = require('factory-girl')
const { User } = require('../../models')
factory.define('user', User, {
name: factory.sequence('User.name', n => `user_${n}`),
email: factory.sequence('User.email', n => `user_${n}@test.com`),
status: 'active'
})
// Usage in tests
const testUser = await factory.create('user', {
role: 'admin'
})
Test Hook Optimization
Global test hooks can be placed in test/hooks.js
:
const sinon = require('sinon')
const chai = require('chai')
before(() => {
// Global sinon sandbox
global.sandbox = sinon.createSandbox()
// Chai plugins
chai.use(require('sinon-chai'))
chai.use(require('chai-as-promised'))
})
afterEach(() => {
global.sandbox.restore()
})
Performance Testing Integration
Example of using autocannon
for stress testing:
// test/performance/api.test.js
const autocannon = require('autocannon')
const app = require('../../app')
describe('Performance', () => {
let server
before(() => {
server = app.listen(0)
})
after(() => {
server.close()
})
it('should handle 1000 requests', async () => {
const port = server.address().port
const result = await autocannon({
url: `http://localhost:${port}`,
connections: 10,
duration: 5
})
console.log(result)
expect(result.errors).to.equal(0)
})
})
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:接口测试与自动化方案
下一篇:测试覆盖率统计与分析