Sinon存根需要多次

时间:2019-05-13 10:02:35

标签: unit-testing jestjs google-cloud-functions sinon

因此,我正在针对Google Cloud Functions进行测试,并且很难对具有不同行为的node_modules库进行存根。

在测试文件的开头,我在firebase-admin上有一个boforeAll库的存根。

然后,我必须进行不同的测试it should export idinInitRequestidin issue,这与要测试的文件'../src/index'(即云功能)的相应要求有关。

第一个按预期方式工作。正确与我的callsFake进行存根。

问题在第二次测试时出现。在第二个测试中,我模拟了Cloud Function 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],
            (...)

从日志中我们可以看到,在第一次执行中它是正确的存根,而在第二次执行中则没有。

在每个测试中要求使用该功能的原因是由于库在不同测试下可能具有不同的行为。

在第一次提出要求后,我不知道如何再次对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');
    });
  });
});

1 个答案:

答案 0 :(得分:0)

在解释存根和模拟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');
    });
  });
});

如果您有其他解决方法,欢迎分享。