简体   繁体   English

如何在 Firebase 云函数中模拟辅助函数?

[英]How to mock helper functions in Firebase Cloud Functions?

I am currently exploring unit-testing in Firebase Cloud Functions and ran into a use-case that seems like it would be quite frequent but isn't covered by the official documentation.我目前正在探索 Firebase Cloud Functions 中的单元测试,并遇到了一个似乎很频繁但官方文档未涵盖的用例。

When writing Cloud Functions for various processes and triggers, we usually use separate helper functions to help us write more reusable code.在为各种进程和触发器编写 Cloud Functions 时,我们通常会使用单独的辅助函数来帮助我们编写更多可重用的代码。 For example:例如:

// index.ts
import * as functions from "firebase-functions";

function add(num1: number, num2: number) {
    return num1 + num2;
}

exports.getSum = functions.https.onCall((data, context) => {
    return {
        result: add(data.num1, data.num2)
    }
})

When I now want to test getSum , I would have to import it into my test file and make an assertion.当我现在想测试getSum时,我必须将它导入我的测试文件并做出断言。 However this is where I encounter the issue:但是,这是我遇到问题的地方:

How do I assert that add has been called in getSum ?如何断言add已在getSum中调用? Or better: how do I mock add ?或者更好:我如何模拟add

The only workaround I have found so far is exporting add as well and then modifying the code to call this.add instead of just add like so:到目前为止,我发现的唯一解决方法是导出add ,然后修改代码以调用this.add而不是像这样add

// index.ts
import * as functions from "firebase-functions";

export function add(num1: number, num2: number) {
    return num1 + num2;
}

exports.getSum = functions.https.onCall((data, context) => {
    return {
        // @ts-ignore
        result: this.add(data.num1, data.num2)
    }
})

However this solution is not ideal as I 1. can't guarantee that this isn't undefined (which is also why I need to // @ts-ignore it) and 2. need to modify the original code to make testing work.然而这个解决方案并不理想,因为我 1. 不能保证this不是未定义的(这也是我需要// @ts-ignore它的原因)和 2. 需要修改原始代码以使测试工作。

Is there any way to make this work without modifying the functions code?有没有办法在不修改功能代码的情况下完成这项工作? Any best practice for testing these kind of helper functions?测试这些辅助函数的任何最佳实践? Thank you in advance!先感谢您!

Here is the full unit test code I have used for the workaround:这是我用于解决方法的完整单元测试代码:

// index.unit.test.ts
const testEnvironment = require("firebase-functions-test")(
  {
    databaseURL: "",
        storageBucket: "",
        projectId: "",
    },
    "credentials.json"
  );
  const myFunctions = require("../src/index");


describe("getSum", () => {
    let wrapper: any, group: any;

    beforeAll(() => {
        group = myFunctions.addition
        wrapper = testEnvironment.wrap(group.getSum);
    });

    it("adds two numbers", () => {    
        group.add = jest.fn()
    
        wrapper({ num1: 2, num2: 2})

        expect(group.add).toHaveBeenCalled()
    });
});

You can use rewire package to mock the add function without modifying your code.您可以使用rewire package 来模拟add function 而无需修改代码。 For simplicity, I will use offline mode to test the code.为简单起见,我将使用离线模式来测试代码。 Just to demonstrate how to mock the add function.只是为了演示如何模拟add function。

Eg例如

index.ts : index.ts

import * as functions from "firebase-functions";

function add(num1: number, num2: number) {
  return num1 + num2;
}

exports.getSum = functions.https.onCall((data, context) => {
  return {
    result: add(data.num1, data.num2),
  };
});

index.unit.test.ts

const testEnvironment = require("firebase-functions-test")();
const rewire = require("rewire");

describe("getSum", () => {
  it("adds two numbers", () => {
    const mod = rewire("./");
    const mAdd = jest.fn().mockReturnValueOnce(666);
    mod.__set__("add", mAdd);
    const wrapper = testEnvironment.wrap(mod.getSum);
    const actual = wrapper({ num1: 2, num2: 2 });
    console.log(actual);
    expect(actual).toEqual({ result: 666 });
    expect(mAdd).toBeCalledWith(2, 2);
  });
});

npm script: npm 脚本:

"test:cjs": "ts-node -O '{\"module\":\"commonjs\"}' node_modules/jest/bin/jest.js"

Run unit test with coverage report使用覆盖率报告运行单元测试

npm run test:cjs -- --coverage ./index.unit.test.ts

unit test result:单元测试结果:

{"severity":"WARNING","message":"Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing firebase-admin will fail"}
 PASS  stackoverflow/65763396/index.unit.test.ts
  getSum
    ✓ adds two numbers (433ms)

  console.log
    { result: 666 }

      at Object.<anonymous> (stackoverflow/65763396/index.unit.test.ts:11:13)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |       0 |        0 |       0 |       0 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.316s, estimated 3s

package versions: package 版本:

"devDependencies": {
    "@types/jest": "^25.2.1",
    "firebase-functions-test": "^0.2.3",
    "jest": "^25.5.4",
    "rewire": "^5.0.0",
    "ts-jest": "^25.5.1",
    "ts-node": "^9.1.1",
    "typescript": "^3.9.2"
  },
  "dependencies": {
    "firebase": "^7.4.0",
    "firebase-admin": "^9.4.2",
    "firebase-functions": "^3.13.1"
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM