Firebase functions 4 테스팅, mocha, chai

남궁현·2022년 1월 28일
0

Music shorts

목록 보기
4/8
post-thumbnail

TDD를 하고 싶지만 우선은 임의로 테스트를 해볼 함수를 먼저 만들고 그 후에 테스트를 해보겠다. (DDT?)

// src/index.ts
import {https} from "firebase-functions";
import {HttpsError} from "firebase-functions/v1/https";

export const isRunning = https.onCall(async (data, context) => {
  // 데이터 없으면 차단
  if (!data) throw new HttpsError("data-loss", "데이터가 없습니다.");
  // 비로그인 차단
  if (!context.auth)
    throw new HttpsError("unauthenticated", "로그인이 필요한 작업입니다.");
  // 비동기 테스트를 위한 1초 딜레이
  await new Promise(res => setTimeout(res, 1000));

  return "server is running";
});

이 함수에 대해서 4가지를 테스트 해볼 것이다.

  • 결과의 타입이 string 인지
  • 결과가 "server is running"인지
  • data가 없으면 오류를 던지는지
  • 비 로그인시 오류를 던지는지

패키지 설치

  • mocha // 테스트 프레임워크
  • chai // assertion 라이브러리
  • ts-node // 빌드하지 않고 typescript를 바로 실행시킬수있는 라이브러리, 테스트코드를 빌드하지 않고 실행하기 위함
  • firebase-functions-test // 테스트 환경에서 firebase functions를 실행하게 해줌
    yarn add -D mocha chai @types/mocha @types/chai ts-node firebase-functions-test

tsconfig.json 수정

tsconfig.dev.json

개발 단계에서 test 폴더안에 파일들을 실행할 수 있게함

tsconfig.json

production 환경에서 테스트코드를 사용하지 않을 것이기 때문에 exclude에 추가해준다.

테스트 코드 작성

// test/index.test.ts
import {expect} from "chai";
import firebaseFunctionsTest from "firebase-functions-test";
import {auth} from "firebase-functions/v1";

// onCall 함수를 실행해주는 모듈
const testFunctions = firebaseFunctionsTest();

// description은 그룹화 라고 보면됨, 보통 "/", "/api/auth"등 폴더, 라우팅 위치등을 title로 사용함
describe("/", () => {
  let Functions: any;
  let testUser: auth.UserRecord;

  // "/"이 스코프 안에 테스트 함수들이 실행되기 전 가장먼저 실행되는 함수, 생상자 같은 느낌
  before(() => {
    // import를 사용하지 않고 require을 사용하는 이유는
    // import로 불러오면 "firebaseFunctionsTest()"이 함수등
    // 기본적으로 필요한 setup들이 있는데 그보다 전에 호출이 되어 test환경이 아닌 dev환경으로 인식됨
    // 다음 챕터에서 확인할 수 있음
    Functions = require("../src/index.ts");
    // 임의의 테스트 유저 생성
    testUser = testFunctions.auth.makeUserRecord({id: "test_user"});
  });

  // 이 스코프 마지막함수 실행후에 실행되는 함수, 소멸자 같은 느낌
  after(async () => {
    // testFunctions 초기화
    await testFunctions.cleanup();
  });

  // context는 description과 일치 하는 기능을 갖지만 주로 실제 실행할 함수의 이름을 title로 사용한다.
  context("isRunning", () => {
    // it는 실제 테스트함수
    it("결과의 타입은 string입니다.", async () => {
      // 실행할 함수를 testFunctions.wrap로 감싸면 실행할 수 있다.
      const result = await testFunctions.wrap(Functions.isRunning)(
        // Data
        {
          testData: "hello",
        },
        // Context
        {auth: testUser},
      );
      // a()함수는 타입체크
      expect(result).to.be.a("string");
      // console.log(result) <= 이러면 안됨
      // async 함수안에서 test할때는 함수의 마지막 줄이 무조건 expect여야함 아닐시 timeout에러 발생
    });

    it("결과값은 server is running 입니다.", async () => {
      const result = await testFunctions.wrap(Functions.isRunning)(
        {
          testData: "hello",
        },
        {auth: testUser},
      );
      expect(result).to.equal("server is running");
    });

    it("Data가 없으면 오류가 발생시킵니다.", async () => {
      // 에러 채크는 .catch후 result를 error로 매핑한다.
      const result = await testFunctions
        .wrap(Functions.isRunning)(undefined, {auth: testUser})
        .catch((e: any) => e);
      // 그후 타입이 error인지 체크
      expect(result).to.be.a("error");
    });

    it("비로그인시 오류가 발생합니다.", async () => {
      const result = await testFunctions
        .wrap(Functions.isRunning)({
          testData: "hello",
        })
        .catch((e: any) => e);
      expect(result).to.be.a("error");
    });
  });
});

실행

package.json에 scripts안에 다음과 같은 스크립트를 추가해준다.

"test": "mocha --reporter spec test/**/*.test.ts -r ts-node/register ",

그후 yarn test명령어로 실행시키면 정상적으로 작동한다.

추가사항

import에러가 발생하여 tsconfig.json을 이와 같이 수정함

0개의 댓글