更新:我有一个基本的异步函数,我想单位测试。我正在使用NPM的nock来模拟服务器的响应。每次我运行这个小测试脚本时,我都会收到主机名不确定的错误:当我尝试从测试中调用功能时,我不明白为什么会遇到此错误。当我运行脚本以及在Postman中打电话时,它可以正常工作。我觉得我正在寻找超级基础的东西?
这是单元测试代码:
const assert = require('chai').assert;
const getSorted = require('../src/karma').getSorted;
const nock = require('nock');
describe('Sorting', function () {
it('should return karma in DESC order', function (done) {
let expectedKarmas = { users: ['nikki', 'person', 'nolan'], karmas: ['3', '2', '1'] }
let karmaApi = nock(`http://server:4567/`);
karmaApi.get('/getsorted/DESC')
.reply(200,
[['bmlra2k=', '3'], ['cGVyc29u', '2'], ['bm9sYW4=', '1']]
);
let recievedKarmas = getSorted("DESC");
console.log('recievedKarmas:::', recievedKarmas)
assert.equal(recievedKarmas, expectedKarmas);
});
});
这是原始功能:
let axios = require("axios");
let atob = require('atob');
//end point is "server:4567"
let KARMABOT_API_ENDPOINT = process.env.KARMABOT_API_ENDPOINT;
module.exports = {
getSorted: async function (direction) {
if (direction !== "ASC" && direction !== "DESC") {
console.error("INVALID SORTING DIRECTION: %s. PLEASE PROVIDE ASC OR DESC", direction);
return;
}
try {
let url = `http://${KARMABOT_API_ENDPOINT}/getsorted/${direction}`;
console.log('URL IS:', url)
let jsonResult = await axios.get(url);
let sorted = { users: [], karmas: [] };
jsonResult.data.forEach(element => {
//users are stored in the database encoded, atob() decodes them back into strings
sorted.users.push(atob(element[0]));
sorted.karmas.push(element[1]);
});
return sorted
} catch (error) {
console.error('ERROR HERE', error)
}
}
完整错误:
Sorting
URL IS: http://undefined/getsorted/DESC
recievedKarmas::: Promise { <pending> }
1) should return karma in DESC order
ERROR HERE { Error: getaddrinfo ENOTFOUND undefined undefined:80
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:56:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'undefined',
host: 'undefined',
port: 80,
config:
{ url: 'http://undefined/getsorted/DESC',
method: 'get',
headers:
{ Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/0.19.0' },
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
data: undefined },
request:
Writable {
_writableState:
WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: false,
errorEmitted: false,
emitClose: true,
bufferedRequestCount: 0,
corkedRequestsFree: [Object] },
writable: true,
_events:
[Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError] },
_eventsCount: 2,
_maxListeners: undefined,
_options:
{ protocol: 'http:',
maxRedirects: 21,
maxBodyLength: 10485760,
path: '/getsorted/DESC',
method: 'GET',
headers: [Object],
agent: undefined,
auth: undefined,
hostname: 'undefined',
port: 80,
nativeProtocols: [Object],
pathname: '/getsorted/DESC',
proto: 'http',
host: 'undefined:80' },
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function],
_currentRequest:
ClientRequest {
_events: [Object],
_eventsCount: 6,
_maxListeners: undefined,
output: [],
outputEncodings: [],
outputCallbacks: [],
outputSize: 0,
writable: true,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
socket: [Socket],
connection: [Socket],
_header:
'GET /getsorted/DESC HTTP/1.1rnAccept: application/json, text/plain, */*rnUser-Agent: axios/0.19.0rnHost: undefinedrnConnection: closernrn',
_onPendingData: [Function: noopPendingOutput],
agent: [Agent],
socketPath: undefined,
timeout: undefined,
method: 'GET',
path: '/getsorted/DESC',
_ended: false,
res: null,
aborted: undefined,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
_redirectable: [Circular],
[Symbol(isCorked)]: false,
[Symbol(outHeadersKey)]: [Object] },
_currentUrl: 'http://undefined:80/getsorted/DESC' },
response: undefined,
isAxiosError: true,
toJSON: [Function] }
0 passing (24ms)
1 failing
1) Sorting
should return karma in DESC order:
AssertionError: expected {} to equal { Object (users, karmas) }
at Context.<anonymous> (test/test-karma.js:21:16)
npm ERR! Test failed. See above for more details.
因此,我知道测试至少要击中原始getSorted()
功能,因为ERROR HERE
已记录。但是我不明白为什么主机和主机名不确定。我明确说"服务器:4567"。
我认为我犯了一个愚蠢的错误,因为这只是我试图从基本单元测试中调用功能。
感谢您的帮助!
保持测试真正统一。您不应在单位测试中直接调用HTTP调用。这是因为您需要另一台服务器运行,因此它不再统一。
有避免这种情况的叛变方法。
1- proxyquire参考:https://www.npmjs.com/package/proxyquire
需要您的文件进行测试,但用您自己替换一些依赖项。
不利的一面是,您不确定要替换哪个ProxyQuire。您将其委派到另一个图书馆。
const proxyquire = require('proxyquire');
const assert = require('chai').assert;
const fakeStub = {} // This is some sort of fake or stub that prevent http call.
const getSorted = proxyquire('../src/karma', {axios: fakeStub }).getSorted; // Requires using your fake
describe('Sorting', function () {
// If your test framework allow async function in test use it instead of done.
it('should return karma in DESC order', async function () {
let expectedKarmas = { users: ['nikki', 'person', 'nolan'], karmas: ['3', '2', '1'] }
let recievedKarmas = await getSorted("DESC"); // since it is async you have to wait otherwise it may be a promise
assert.equal(recievedKarmas, expectedKarmas);
});
});
2-添加覆盖钩
更多的控制权,并且可能具有某种特殊模式,可以避免使用Axios。
很难管理require
的状态。再次需要时,模块轴可能仍被覆盖。
let axios = require("axios");
let atob = require('atob');
//end point is "server:4567"
let KARMABOT_API_ENDPOINT = process.env.KARMABOT_API_ENDPOINT;
module.exports = {
overrideAxiosHook: (fakeAxios) => {
axios = fakeAxios
}
// return the users sorted by amount of karma in directions of ASC (ascending) or DESC (descending)
// object returned has a users array and a karmas array
getSorted: async function (direction) {
if (direction !== "ASC" && direction !== "DESC") {
console.error("INVALID SORTING DIRECTION: %s. PLEASE PROVIDE ASC OR DESC", direction);
return;
}
try {
let url = `http://${KARMABOT_API_ENDPOINT}/getsorted/${direction}`;
let jsonResult = await axios.get(url);
let sorted = { users: [], karmas: [] };
jsonResult.data.forEach(element => {
//users are stored in the database encoded, atob() decodes them back into strings
sorted.users.push(atob(element[0]));
sorted.karmas.push(element[1]);
});
return sorted
} catch (error) {
console.error('ERROR HERE', error)
}
}
}
测试
const assert = require('chai').assert;
const {getSorted, overrideAxiosHook} = require('../src/karma');
const fakeStub = {} // This is some sort of fake or stub that prevent http call.
describe('Sorting', function () {
before((done) => {
overrideAxiosHook(fakeStub)
done();
});
//If using done
it('should return karma in DESC order', function (done) {
let expectedKarmas = { users: ['nikki', 'person', 'nolan'], karmas: ['3', '2', '1'] }
getSorted("DESC").then((recievedKarmas) => {
assert.equal(recievedKarmas, expectedKarmas);
done();
});
});
});
3-在模块中添加axois并使用this.axios
与#2相同的缺点,但功能较少
let atob = require('atob');
//end point is "server:4567"
let KARMABOT_API_ENDPOINT = process.env.KARMABOT_API_ENDPOINT;
module.exports = {
axios: require("axios")
// return the users sorted by amount of karma in directions of ASC (ascending) or DESC (descending)
// object returned has a users array and a karmas array
getSorted: async function (direction) {
if (direction !== "ASC" && direction !== "DESC") {
console.error("INVALID SORTING DIRECTION: %s. PLEASE PROVIDE ASC OR DESC", direction);
return;
}
try {
let url = `http://${KARMABOT_API_ENDPOINT}/getsorted/${direction}`;
let jsonResult = await this.axios.get(url);
let sorted = { users: [], karmas: [] };
jsonResult.data.forEach(element => {
//users are stored in the database encoded, atob() decodes them back into strings
sorted.users.push(atob(element[0]));
sorted.karmas.push(element[1]);
});
return sorted
} catch (error) {
console.error('ERROR HERE', error)
}
}
}
4-使用真实的HTTP调用
下行需要另一台运行服务器。
process.env.KARMABOT_API_ENDPOINT = 'server:4567';
const assert = require('chai').assert;
const getSorted = require('../src/karma').getSorted;
describe('Sorting', function () {
it('should return karma in DESC order', async function () {
let expectedKarmas = { users: ['nikki', 'person', 'nolan'], karmas: ['3', '2', '1'] }
let recievedKarmas = await getSorted("DESC");
assert.equal(recievedKarmas, expectedKarmas);
});
});