使用proxyquire,sinon和mocha。
我能够在第一次调用fetch时获取存根。但是在第二次提取调用中,这是递归的,我无法断言它。从输出看,断言可能在测试结束之前运行。在断言后,您将在second fetch
控制台中看到此信息。
index.js
var fetch = require('node-fetch');
function a() {
console.log('function a runs');
fetch('https://www.google.com')
.then((e) => {
console.log('first fetch');
b();
})
.catch((e)=> {
console.log('error')
});
}
function b() {
fetch('https://www.google.com')
.then((e) => {
console.log('second fetch');
})
.catch((e)=> {
console.log('error')
});
}
a()
测试:
describe('fetch test demo', ()=> {
it('fetch should of called twice', (done)=> {
fetchStub = sinon.stub();
fetchStub2 = sinon.stub();
fetch = sinon.stub();
fetchStub.returns(Promise.resolve('hello'));
fetchStub2.returns(Promise.resolve('hi'));
var promises = [ fetchStub, fetchStub2 ]
fetch.returns(Promise.all(promises));
proxy('../index', {
'node-fetch': fetch
});
fetch.should.have.been.callCount(2);
done()
});
});
fetch test demo
function a runs
1) fetch should of called twice
first fetch
second fetch
lifx alert test
- fetch should of called three times
when rain change is over 50%
- should run fetch twice
0 passing (78ms)
2 pending
1 failing
1) fetch test demo fetch should of called twice:
expected stub to have been called exactly twice, but it was called once
stub(https://www.google.com) => [Promise] { } at a (/home/one/github/lifx-weather/foobar.js:5:3)
AssertionError: expected stub to have been called exactly twice, but it was called once
stub(https://www.google.com) => [Promise] { } at a (foobar.js:5:3)
at Context.it (test/bar.js:22:28)
答案 0 :(得分:3)
@dman,因为你更新了你的测试用例,我欠你一个更新的答案。尽管如此,这种情况仍然是非正统的 - 看起来你似乎想要忽略“重力法则”,即使你知道它就在你面前。
我会尝试尽可能具有描述性。您有两个功能是按设计执行异步内容。 a()按顺序调用 b() - 这不是recursion。两种功能都不会在完成/失败时通知其呼叫者,即它们被视为即发即弃。
现在,让我们来看看你的测试场景。您创建3个存根。其中两个解析为一个字符串,另一个使用Promise.all()
组合它们的执行。接下来,您代理'node-fetch'模块
proxy('./updated', {
'node-fetch': fetch
});
使用存根返回存根1和1的组合执行。 2.现在,如果在任一函数中打印出 fetch 的已解析值,您将看到它是一个存根数组而不是字符串。
function a () {
console.log('function a runs');
fetch('http://localhost')
.then((e) => {
console.log('first fetch', e);
b();
})
.catch((e) => {
console.log('error');
});
}
我猜这不是预期的输出。但是,让我们继续前进,因为这不会杀死你的测试。接下来,您已将断言与 done()语句一起添加。
fetch.should.have.been.callCount(2);
done();
这里的问题是,无论您是否使用完成(),效果都将完全相同。您正在同步模式下执行您的方案。当然在这种情况下,断言总是会失败。但重要的是要了解为什么。
因此,让我们重写您的场景,以模仿您要验证的行为的异步特性。
'use strict';
const chai = require('chai');
const sinon = require('sinon');
const SinonChai = require('sinon-chai');
chai.use(SinonChai);
chai.should();
const proxy = require('proxyquire');
describe('fetch test demo', () => {
it('fetch should of called twice', (done) => {
var fetchStub = sinon.stub();
var fetchStub2 = sinon.stub();
var fetch = sinon.stub();
fetchStub.returns(Promise.resolve('hello'));
fetchStub2.returns(Promise.resolve('hi'));
var promises = [fetchStub, fetchStub2];
fetch.returns(Promise.all(promises));
proxy('./updated', {
'node-fetch': fetch
});
setTimeout(() => {
fetch.should.have.been.callCount(2);
done();
}, 10);
});
});
正如您所看到的,唯一的变化是将断言包装在计时器块中。没什么 - 只要等待10毫秒然后断言。现在测试按预期通过。为什么呢?
嗯,对我来说这很简单。您希望测试2个顺序执行的异步函数,并仍然以同步模式运行断言。这听起来很酷,但它不会发生:)所以你有两个选择:
可以做到。我已经重新考虑了你提供的文件了 可以执行。
index.js
const fetch = require('node-fetch'); const sendAlert = require('./alerts').sendAlert; module.exports.init = function () { return new Promise((resolve, reject) => { fetch('https://localhost') .then(function () { sendAlert().then(() => { resolve(); }).catch( e => reject(e) ); }) .catch(e => { reject(e); }); }); };
alerts.js
const fetch = require('node-fetch'); module.exports.sendAlert = function () { return new Promise((resolve, reject) => { fetch('https://localhost') .then(function () { resolve(); }).catch((e) => { reject(e); }); }); };
test.js
'use strict'; const chai = require('chai'); const sinon = require('sinon'); const SinonChai = require('sinon-chai'); chai.use(SinonChai); chai.should(); const proxy = require('proxyquire'); describe.only('lifx alert test', () => { it('fetch should of called twice', (done) => { var body = { 'hourly': { data: [{ time: 1493413200, icon: 'clear-day', precipIntensity: 0, precipProbability: 0, ozone: 297.17 }] } }; var response = { json: () => { return body; } }; const fetchStub = sinon.stub(); fetchStub.returns(Promise.resolve(response)); fetchStub['@global'] = true; var stubs = { 'node-fetch': fetchStub }; const p1 = proxy('./index', stubs); p1.init().then(() => { try { fetchStub.should.have.been.calledTwice; done(); } catch (e) { done(e); } }).catch((e) => done(e)); }); });
你要做的事情虽然有点不正统 良好的单元测试实践。虽然 proxyquire 支持此功能 通过名为全局覆盖的功能进行存根的模式,它是 explained here为什么在下山之前应该三思而后行 这条路。
为了让你的例子通过测试,你只需要添加一个 Sinon存根的额外属性称为 @global 并将其设置为 真正。此标志将覆盖 require()缓存机制 无论调用哪个模块,都使用提供的存根。
所以,虽然你所要求的可以做,但我必须同意 评论您的问题的用户,这不应该是 采用作为构建测试的正确方法。
答案 1 :(得分:0)
我找到了另一种方法来完成任务。 可能对某人有用。
describe('Parent', () => {
let array: any = [];
before(async () => {
array = await someAsyncDataFetchFunction();
asyncTests();
});
it('Dummy test to run before()',async () => {
expect(0).to.equal(0); // You can use this test to getting confirm whether data fetch is completed or not.
});
function asyncTests() {
array.forEach((currentValue: any) => {
describe('Child', async () => {
it('Test '+ currentValue ,() => {
expect(currentValue).to.equal(true);
})
})
});
}
});
这就是我在数组的每个元素上实现断言的方式。 (正在异步获取数组数据)。