Sinon存根需要多次
Sinon stub require multiple times
所以我正在为 Google Cloud Functions 进行测试,但我很难对具有不同行为的 node_modules 库进行存根。
在测试文件的开头,我在 boforeAll
上有一个 firebase-admin
库的存根。
然后我必须对 it should export idinInitRequest
和 idin issue
进行不同的测试,它对应被测试文件的要求 '../src/index'
,这是云函数。
第一个按预期工作。正确地用我的 callsFake
存根。
第二次测试时出现问题。在第二个测试中,我正在模拟云函数 node-idin-beta
中使用的另一个库。在此测试中,firebase-admin
库未被存根。事实上,它的行为就像它根本没有存根一样,使用它所有的默认方法。函数中的 console.log(admin)
显示为:
console.log src/app.ts:122
{ firestore: [Function: firestore], auth: [Function: auth] }
console.log src/app.ts:122
FirebaseApp {
firebaseInternals_:
FirebaseNamespaceInternals {
firebase_:
FirebaseNamespace {
__esModule: true,
credential: [Object],
SDK_VERSION: '6.3.0',
Promise: [Function: Promise],
INTERNAL: [Circular],
(...)
从日志中我们可以看出,第一次执行是stubbing正确,第二次却没有。
要求在每个测试中使用函数的原因是库在不同测试下可能具有不同的行为。
我不知道如何在第一个 require 之后再次存根 firebase-admin
。
这里我留下一段代码:
import { ContextOptions } from 'firebase-functions-test/lib/main';
import setup from './lib/setup.lib';
const { admin, sinon, assert, testEnv } = setup;
describe('Cloud Functions', (): void => {
let myFunctions;
let adminInitStub;
beforeAll((): void => {
// [START stubAdminInit]
// If index.js calls admin.initializeApp at the top of the file,
// we need to stub it out before requiring index.js. This is because the
// functions will be executed as a part of the require process.
// Here we stub admin.initializeApp to be a dummy function that doesn't do anything.
adminInitStub = sinon.stub(admin, 'initializeApp');
process.env.FUNCTION_NAME = 'idinInitRequest';
// [END stubAdminInit]
});
afterAll((): void => {
// Restore admin.initializeApp() to its original method.
adminInitStub.restore();
// Do other cleanup tasks.
process.env.FUNCTION_NAME = '';
myFunctions = undefined;
testEnv.cleanup();
});
afterEach((): void => {
myFunctions = undefined;
// Restore mocks
jest.resetModules();
});
describe('idinInitRequest', (): void => {
it('it should export idinInitRequest', (): void => {
adminInitStub = adminInitStub.callsFake((): any => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
}));
myFunctions = require('../src/index');
const cFunction = require('../src/idinInitRequest');
assert.isObject(myFunctions);
assert.include(myFunctions, { idinInitRequest: cFunction });
});
it('idin issue', async (): Promise<void> => {
jest.mock('node-idin-beta', (): { [key: string]: any } => ({
getTransactionResponse: (): Promise<any> => Promise.reject('shiat'),
}));
adminInitStub = adminInitStub.callsFake((): any => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
}));
myFunctions = require('../src/index');
const wrapped = testEnv.wrap(myFunctions.idinInitRequest);
const onCallObjects: [any, ContextOptions] = [
{ issuerId: 'issuer', merchantReturnUrl: 'url' },
{ auth: { uid: '32344' } },
];
await expect(wrapped(...onCallObjects)).rejects.toThrow('There was an error connecting to the idin issuer');
});
});
});
在解释了存根和模拟 here 之间的区别之后,我决定也模拟 firebase-admin
因为是的,这是一个预定义的行为,但它会根据测试而改变。它正在工作。这是代码:
describe('Cloud Functions', (): void => {
let myFunctions;
beforeAll((): void => {
process.env.FUNCTION_NAME = 'idinInitRequest';
});
afterAll((): void => {
process.env.FUNCTION_NAME = '';
myFunctions = undefined;
testEnv.cleanup();
});
afterEach((): void => {
myFunctions = undefined;
// Restore mocks
jest.resetModules();
});
describe('idinInitRequest', (): void => {
it('it should export idinInitRequest', (): void => {
jest.mock('firebase-admin', (): { [key: string]: any } => ({
initializeApp: () => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
})
}));
myFunctions = require('../src/index');
const cFunction = require('../src/idinInitRequest');
assert.isObject(myFunctions);
assert.include(myFunctions, { idinInitRequest: cFunction });
});
it('idin issue', async (): Promise<void> => {
jest.mock('node-idin-beta', (): { [key: string]: any } => ({
getTransactionResponse: (): Promise<any> => Promise.reject('shiat'),
}));
jest.mock('firebase-admin', (): { [key: string]: any } => ({
initializeApp: () => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
})
}));
myFunctions = require('../src/index');
const wrapped = testEnv.wrap(myFunctions.idinInitRequest);
const onCallObjects: [any, ContextOptions] = [
{ issuerId: 'issuer', merchantReturnUrl: 'url' },
{ auth: { uid: '32344' } },
];
await expect(wrapped(...onCallObjects)).rejects.toThrow('There was an error connecting to the idin issuer');
});
});
});
如果您有其他解决方法,欢迎分享。
所以我正在为 Google Cloud Functions 进行测试,但我很难对具有不同行为的 node_modules 库进行存根。
在测试文件的开头,我在 boforeAll
上有一个 firebase-admin
库的存根。
然后我必须对 it should export idinInitRequest
和 idin issue
进行不同的测试,它对应被测试文件的要求 '../src/index'
,这是云函数。
第一个按预期工作。正确地用我的 callsFake
存根。
第二次测试时出现问题。在第二个测试中,我正在模拟云函数 node-idin-beta
中使用的另一个库。在此测试中,firebase-admin
库未被存根。事实上,它的行为就像它根本没有存根一样,使用它所有的默认方法。函数中的 console.log(admin)
显示为:
console.log src/app.ts:122
{ firestore: [Function: firestore], auth: [Function: auth] }
console.log src/app.ts:122
FirebaseApp {
firebaseInternals_:
FirebaseNamespaceInternals {
firebase_:
FirebaseNamespace {
__esModule: true,
credential: [Object],
SDK_VERSION: '6.3.0',
Promise: [Function: Promise],
INTERNAL: [Circular],
(...)
从日志中我们可以看出,第一次执行是stubbing正确,第二次却没有。
要求在每个测试中使用函数的原因是库在不同测试下可能具有不同的行为。
我不知道如何在第一个 require 之后再次存根 firebase-admin
。
这里我留下一段代码:
import { ContextOptions } from 'firebase-functions-test/lib/main';
import setup from './lib/setup.lib';
const { admin, sinon, assert, testEnv } = setup;
describe('Cloud Functions', (): void => {
let myFunctions;
let adminInitStub;
beforeAll((): void => {
// [START stubAdminInit]
// If index.js calls admin.initializeApp at the top of the file,
// we need to stub it out before requiring index.js. This is because the
// functions will be executed as a part of the require process.
// Here we stub admin.initializeApp to be a dummy function that doesn't do anything.
adminInitStub = sinon.stub(admin, 'initializeApp');
process.env.FUNCTION_NAME = 'idinInitRequest';
// [END stubAdminInit]
});
afterAll((): void => {
// Restore admin.initializeApp() to its original method.
adminInitStub.restore();
// Do other cleanup tasks.
process.env.FUNCTION_NAME = '';
myFunctions = undefined;
testEnv.cleanup();
});
afterEach((): void => {
myFunctions = undefined;
// Restore mocks
jest.resetModules();
});
describe('idinInitRequest', (): void => {
it('it should export idinInitRequest', (): void => {
adminInitStub = adminInitStub.callsFake((): any => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
}));
myFunctions = require('../src/index');
const cFunction = require('../src/idinInitRequest');
assert.isObject(myFunctions);
assert.include(myFunctions, { idinInitRequest: cFunction });
});
it('idin issue', async (): Promise<void> => {
jest.mock('node-idin-beta', (): { [key: string]: any } => ({
getTransactionResponse: (): Promise<any> => Promise.reject('shiat'),
}));
adminInitStub = adminInitStub.callsFake((): any => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
}));
myFunctions = require('../src/index');
const wrapped = testEnv.wrap(myFunctions.idinInitRequest);
const onCallObjects: [any, ContextOptions] = [
{ issuerId: 'issuer', merchantReturnUrl: 'url' },
{ auth: { uid: '32344' } },
];
await expect(wrapped(...onCallObjects)).rejects.toThrow('There was an error connecting to the idin issuer');
});
});
});
在解释了存根和模拟 here 之间的区别之后,我决定也模拟 firebase-admin
因为是的,这是一个预定义的行为,但它会根据测试而改变。它正在工作。这是代码:
describe('Cloud Functions', (): void => {
let myFunctions;
beforeAll((): void => {
process.env.FUNCTION_NAME = 'idinInitRequest';
});
afterAll((): void => {
process.env.FUNCTION_NAME = '';
myFunctions = undefined;
testEnv.cleanup();
});
afterEach((): void => {
myFunctions = undefined;
// Restore mocks
jest.resetModules();
});
describe('idinInitRequest', (): void => {
it('it should export idinInitRequest', (): void => {
jest.mock('firebase-admin', (): { [key: string]: any } => ({
initializeApp: () => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
})
}));
myFunctions = require('../src/index');
const cFunction = require('../src/idinInitRequest');
assert.isObject(myFunctions);
assert.include(myFunctions, { idinInitRequest: cFunction });
});
it('idin issue', async (): Promise<void> => {
jest.mock('node-idin-beta', (): { [key: string]: any } => ({
getTransactionResponse: (): Promise<any> => Promise.reject('shiat'),
}));
jest.mock('firebase-admin', (): { [key: string]: any } => ({
initializeApp: () => ({
firestore: (): any => ({
settings: (): void => {},
}),
auth: (): void => { },
})
}));
myFunctions = require('../src/index');
const wrapped = testEnv.wrap(myFunctions.idinInitRequest);
const onCallObjects: [any, ContextOptions] = [
{ issuerId: 'issuer', merchantReturnUrl: 'url' },
{ auth: { uid: '32344' } },
];
await expect(wrapped(...onCallObjects)).rejects.toThrow('There was an error connecting to the idin issuer');
});
});
});
如果您有其他解决方法,欢迎分享。