В настоящее время я учусь тестировать модули узлов. В последние дни я задал пару вопросов здесь, на StackOverflow, о том, как имитировать модули узлов, чтобы проверить, например, что происходит в предложении .then () обещания.
Я получил несколько замечательных предложений от сообщества о том, как справиться с этим, и я зашел довольно далеко. Однако есть еще кое-что, что я не могу обернуть, и это связано с асинхронными вызовами.
Например, у меня сейчас есть следующий код для добавления поста:
const makeRequestStructure = require('./modules/makeRequestStructure.js').makeRequestStructure
const normalizeFinalResponse = require('./modules/normalizeFinalResponse.js').normalizeFinalResponse
const doARequest = require('./modules/doARequest.js').doARequest
exports.addPost = (event) => {
const requestStructure = makeRequestStructure('POST', '/posts')
const requestPostData = {
title: event.body.title,
content: event.body.content
}
return doARequest(requestStructure, requestPostData).then((res) => {
const finalResponse = normalizeFinalResponse(200, res)
return finalResponse
}).catch((err) => {
const finalResponse = normalizeFinalResponse(400, err)
return finalResponse
})
}
Вспомогательные функции, необходимые для запуска этого файла:
makeRequestStructure.js
(находится по адресу ./modules/makeRequestStructure.js
)
require('dotenv').config()
const { HOST, PORT } = process.env
module.exports.makeRequestStructure = function (method, path) {
return {
host: HOST,
port: PORT,
method: method,
path: path
}
}
В этом модуле используются переменные окружения, которые я настроил в своем файле .env:
HOST=jsonplaceholder.typicode.com
POST=433
Далее у меня есть файл normalizeFinalResponse.js
и файлы doARequest.js
:
normalizeFinalResponse.js
(находится по адресу ./modules/normalizeFinalResponse.js
)
module.exports.normalizeFinalResponse = function (statusCode, message) {
return {
'statusCode': statusCode,
'body': { message: message }
}
}
doARequest.js
(находится по адресу ./modules/doARequest.js
)
const https = require('https')
module.exports.doARequest = function (params, postData) {
return new Promise((resolve, reject) => {
const req = https.request(params, (res) => {
let body = []
res.on('data', (chunk) => {
body.push(chunk)
})
res.on('end', () => {
try {
body = JSON.parse(Buffer.concat(body).toString())
} catch (e) {
reject(e)
}
resolve(body)
})
})
req.on('error', (err) => {
reject(err)
})
if (postData) {
req.write(JSON.stringify(postData))
}
req.end()
})
}
Теперь этот код довольно прост. Запустив следующий файл, он сделает POST-вызов jsonplaceholder.typicode.com:433/posts
с его телом { body: { title: 'Lorem ipsum', content: 'Lorem ipsum dolor sit amet' } }
const addPost = require('./addPost.js').addPost;
const event = { body: { title: 'Lorem ipsum', content: 'Lorem ipsum dolor sit amet' } }
addPost(event).then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
В модуле addPost
вызывается функция normalizeFinalResponse
для нормализации ответа от API jsonplaceholder. Чтобы проверить это, я создал следующий тестовый файл.
//Dependencies
const mock = require('mock-require')
const sinon = require('sinon')
const expect = require('chai').expect
//Helper modules
const normalizeFinalResponse = require('../modules/normalizeFinalResponse.js')
const doARequest = require('../modules/doARequest.js')
//Module to test
const addPost = require('../addPost.js')
//Mocks
const addPostReturnMock = { id: 101 }
describe('the addPost API call', () => {
it('Calls the necessary methods', () => {
console.log(1)
//Mock doARequest so that it returns a promise with fake data.
//This seems to be running async. The test file continues to run when its not resolved yet
mock('../modules/doARequest', { doARequest: function() {
console.log(2)
return Promise.resolve(addPostReturnMock);
}});
console.log(3)
//Stub functions expected to be called
let normalizeFinalResponseShouldBeCalled = sinon.spy(normalizeFinalResponse, 'normalizeFinalResponse');
//Set a fake eventBody
let event = { body: { title: 'Lorem ipsum', content: 'Lorem ipsum dolor sit amet' } }
//Call the method we want to test and run assertions
return addPost.addPost(event).then((res) => {
expect(res.statusCode).to.eql(200);
sinon.assert.calledOnce(normalizeFinalResponseShouldBeCalled);
})
});
});
Запуск этого тестового файла не соответствует утверждению, поскольку, очевидно, функция normalizeFinalResponse
никогда не вызывается. Когда я использую console.log, они печатаются в порядке 1,3,2.
Это заставляет меня поверить, что функция mock()
еще не завершена, и поэтому она будет фактически вызывать API jsonplaceholder. Но чем все-таки должна была быть вызвана функция normalizeFinalResponse
, верно?
У меня такое чувство, что я пропускаю то, что прямо перед моими глазами. Однако я не могу понять, что это такое. Если вы знаете, что не так с моим тестом, я хотел бы услышать это. Это помогает мне лучше понять написание такого рода тестов.
Мой package.json для справки:
{
"name": "mock-requests-tests",
"version": "0.0.1",
"description": "A test repository so i can learn how to mock requests",
"scripts": {
"test": "mocha --recursive tests/",
"test:watch": "mocha --recursive --watch tests/"
},
"devDependencies": {
"chai": "^4.1.2",
"mock-require": "^3.0.2",
"sinon": "^7.2.2"
}
}