Nightwatch 中的 API 测试
概述
API 测试是一种软件测试,它涉及测试应用程序的 API 层。
API 测试包括测试客户端应用程序和服务器之间的请求和响应。这通常通过向 API 端点发送 HTTP 请求并验证返回的响应来完成。API 测试的主要目标是确保 API 按预期运行,并且它在不同的输入情况下返回正确的数据和错误。
总的来说,API 测试是软件测试中一个重要的方面,它可以确保应用程序 API 层的可靠性和功能,使开发人员能够构建健壮且可扩展的软件应用程序。
它是如何工作的?
要执行 API 测试,需要安装官方的 @nightwatch/apitesting 插件。该插件提供了以下功能
需要 Nightwatch 2.6.4 或更高版本。
安装
1) 从 NPM 安装插件
npm i @nightwatch/apitesting --save-dev
2) 将插件添加到列表中
更新 Nightwatch 配置以将插件添加到列表中
module.exports = {
plugins: ['@nightwatch/apitesting']
// other Nightwatch settings...
}
3) 禁用浏览器会话
我们还需要关闭浏览器会话,因为我们只进行 API 测试。这可以通过在 nightwatch.conf.js 中添加一个用于 API 测试的新环境来实现,如下所示
module.exports = {
// ....
api_testing: {
start_session: false,
webdriver: {
start_process: false,
}
}
}
配置设置
目前,该插件只有一个配置选项,即是否将 HTTP 响应记录到控制台。这可以在 nightwatch.json
(或 nightwatch.conf.js
)配置文件中配置
{
"@nightwatch/apitesting" : {
"log_responses": true
}
}
测试 API 标头和响应
由于 Nightwatch 在幕后使用 supertest
,因此您可以测试不同类型的 REST API 标头和响应。
GET 请求
describe('api testing', function () {
it('get api test', async function({supertest}) {
await supertest
.request("https://petstore.swagger.io/v2")
.get("/pet/findByStatus?status=available")
.expect(200)
.expect('Content-Type', /json/)
.then(function(response){
expect(response._body.length).to.be.greaterThan(0);
});
});
});
POST 请求
describe('api testing', function () {
it('post api test', async function({supertest}) {
await supertest
.request("https://petstore.swagger.io/v2")
.post("/pet")
.send({
"id": 0,
"category": {
"id": 0,
"name": "string"
},
"name": "doggie",
"photoUrls": [
"string"
],
"tags": [
{
"id": 0,
"name": "string"
}
],
"status": "available"
})
.expect(200)
.expect('Content-Type', /json/)
.then(function(response){
expect(response._body.name).to.be.equal("doggie");
});
});
});
运行 API 测试
确保 API 测试是在 environment
中运行的,其中 start_session
和 webdriver -> start_process
设置为 false
。
npx nightwatch <path to tests> --env api_testing
HTML 报告
测试运行后,可以在 HTML 报告中查看结果。
集成的模拟服务器
@nightwatch/apitesting
插件还提供了一个基于 express 的内置模拟服务器,可用于断言传入的 http 请求。
这是一个模拟服务器示例
describe('api testing with supertest in nightwatch POST', function () {
let server;
before(async function(client) {
server = await client.mockserver.create();
server.setup((app) => {
app.post('/api/v1/datasets/', function (req, res) {
res.status(200).json({
id: 'test-dataset-id'
});
});
});
await server.start(3000);
});
after(() => {
server.close();
});
it('demo test', async function(client) {
const req = await server.request()
.post('/api/v1/datasets/')
.send({name: 'medea'})
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/);
await client.assert.deepStrictEqual(server.route.post('/api/v1/datasets/').requestBody, {name: 'medea'});
});
});
模拟服务器 API
const mockServer = await client.mockserver.create()
– 创建一个新的模拟服务器实例await mockServer.setup(definition)
– 使用提供的路由定义设置现有模拟服务器实例 示例await mockServer.setup((app) => { app.get('/api/v1/schemas', function (req, res) { console.log('GET /api/v1/schemas called');
res.status(200).json([ { id: 'test-schema-id1' }, { id: 'test-schema-id2' } ]); }) });await mockServer.start(port)
– 在指定端口启动现有模拟服务器实例await mockServer.route(path)
– 返回指定路由上的 sinon 间谍
断言传入请求
使用 mockServer.route(path)
方法检索指定路由上的间谍。然后,您可以使用 sinon 断言 来断言传入的请求。
示例
考虑前面的模拟服务器设置示例。如果我们想断言 GET /api/v1/schemas
路由被调用,我们可以执行以下操作
it('demo test', async function(client) {
client
.assert.strictEqual(mockServer.route.get('/api/v1/schemas').calledOnce, true, 'called once')
.assert.strictEqual(mockServer.route.get('/api/v1/schemas').calledTwice, false);
});
断言请求标头
我们还可以断言请求标头,例如使用内置的 expect()
断言 API,它基于 chai
it('demo test', async function(client) {
const {requestHeaders} = mockServer.route.get('/api/v1/schemas');
client.expect(requestHeaders).to.have.property('connection', 'close');
});
断言传入的发布数据
我们还可以断言传入的发布数据
- 首先,为模拟服务器设置一个发布路由
await mockServer.setup((app) => {
app.post('/api/v1/datasets/', function (req, res) {
res.status(200).json({
id: 'test-dataset-id'
});
});
});
- 然后使用
mockServer.route.post(path)
方法检索指定路由上的间谍。然后,您可以使用 sinon 断言 来断言传入的请求。
it('demo test', async function(client) {
const {requestBody} = mockServer.route.post('/api/v1/schemas');
await client.assert.deepStrictEqual(requestBody, {name: 'medea'});
});
要等待传入的请求测试,您可以使用 waitUntil()
命令。
使用 waitUntil
的示例
it('demo test', async function(client) {
const timeoutMs = 15000;
const retryIntervalMs = 500;
await client.waitUntil(async function () {
const spy = server.route.get('/api/v1/schemas');
if (spy) {
return spy.calledOnce;
}
return false;
}, timeoutMs, retryIntervalMs, new Error(`time out reached (10000ms) while waiting for API call.`));
});