Firebase 함수 단위 테스트

GonnabeAlright·2021년 12월 16일
0
post-thumbnail

서버 운영을 firebase로 진행하기에 firebase 공식문서를 정리하고자 한다.

Cloud Functions의 단위 테스트

이 페이지에서는 지속적 통합(CI)시스템에 포함될 테스트와 같은 함수용 단위 테스트 작성에 대한 권장사항과 도구를 설명합니다. 쉽게 테스트할 수 있도록 Firebase에서 Cloud Functions 용 Firebase Test SDK를 제공합니다. 이는 firebase-functions-test로 npm에 배포되며 firebase-functions에 대한 동반 테스트 SDK입니다. Cloud functions용 Firebase Test SDK로 다음 작업을 할 수 있습니다.

  • firebase-functions에 필요한 환경 변수를 설정 및 설정 해제하는 등 적절한 테스트 설정과 해제를 처리합니다.
  • SDK가 샘플 데이터이벤트 컨텍스트를 생성하므로 테스트와 관련된 필드만 지정하면 됩니다.

테스트 설정

함수 폴더에서 다음 명령어를 실행하여 firebase-functions-test 및 테스트 프레임워크인 Mocha를 모두 설치합니다.

npm install --save-dev firebase-functions-test
npm install --save-dev mocha

다음으로 함수 폴더 내에 test 폴더를 만들고 여기에 테스트 코드용으로 새 파일을 만든 후 index.test.js와 같은 이름을 지정합니다.

마지막으로 functions/pacakage.json을 수정하여 다음을 추가합니다.

"scripts": {
  "test": "mocha --reporter spec"
}

테스트를 작성한 후에는 함수 디렉터리 내에서 npm test를 실행하여 테스트를 실행할 수 있습니다.

Cloud Functions용 Firebase Test SDK 초기화

firebase-functions-test를 사용하는 방법에는 두 가지가 있습니다.

  1. 온라인 모드(권장): 데이터베이스 쓰기, 사용자 생성 등이 실제로 일어나고 테스트 코드로 결과를 검사할 수 있도록 테스트 전용 firebase 프로젝트와 상호작용하는 테스트를 작성합니다. 즉, 함수에서 사용하는 다른 Google SDK도 작동하게 됩니다.

  2. 오프라인 모드: 부작용 없이 격리된 오프라인 단위 테스트를 작성합니다. 즉, Firebase 제품과 상호작용하는 모든 메서드 호출(예: 데이터베이스 쓰기 또는 사용자 생성)이 스텁 처리되어야 합니다. Cloud Firestore 또는 실시간 데이터베이스 함수가 있으면 테스트 코드의 복잡성이 크게 증가하므로 일반적으로 오프라인 모드를 사용하지 않는 것이 좋습니다.

온라인 모드에서 SDK 초기화(권장)

테스트 프로젝트와 상호작용하는 테스트를 작성하려면 firebase-admin을 통해 앱을 초기화하는 데 필요한 프로젝트 구성 값과 서비스 계정 키 파일의 경로를 제공해야 합니다.

Firebase 프로젝트의 구성 값을 가져오는 방법은 다음과 같습니다.

  1. Firebase Console에서 프로젝트 설정을 엽니다.
  2. 내 앱에서 원하는 앱을 선택합니다.
  3. 오른쪽 창에서 Apple 및 Android 앱용 구성 파일을 다운로드하는 옵션을 선택합니다.

키 파일을 만드는 방법은 다음과 같습니다.

  1. Google Cloud Console의 서비스 계정 창을 엽니다.
  2. App Engine 기본 서비스 계정을 선택하고 오른쪽에 있는 옵션 메뉴를 사용하여 키 만들기를 선택합니다.
  3. 메시지가 나타나면 키 유형으로 JSON을 선택하고 만들기를 클릭합니다.

키 파일을 저장한 후 다음과 같이 SDK를 초기화합니다.

const test = require('firebase-functions-test')({
  databaseURL: 'https://my-project.firebaseio.com',
  storageBucket: 'my-project.appspot.com',
  projectId: 'my-project',  
}, 'path/to/serviceAccountKey.json');

오프라인 모드에서 SDK 초기화

완전 오프라인 테스트를 작성하려면 매개변수 없이 SDK를 초기화하면 됩니다.

// At the top of test/index.test.js
const test = require('firebase-functions-test')();

구성값 모의 처리

함수 코드에서 functions.config()를 사용하는 경우 구성 값을 모의 처리할 수 있습니다. 예를 들어 functions/index.js에 다음 코드가 있는 경우가 여기에 해당합니다.

const functions = require('firebase-functions');
const key = functions.config().stripe.key;

그 후 다음과 같이 테스트 파일 내의 값을 모의 처리할 수 있습니다.

// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});

함수 가져오기

함수를 가져오려면 require를 사용하여 기본 함수 파일을 모듈로 가져옵니다. firebase-functions-test를 초기화하고 구성 값을 모의 처리한 후에만 가져와야 합니다.

// after firebase-functions-test has been initialized.
const myFunctions = require('../index.js');	// relative path to functions code

오프라인 모드에서 firebase-functions-test를 초기화했고 함수 코드에 admin.initializeApp()이 있다면 함수를 가져오기 전에 스텁 처리해야 합니다.

// 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');
// Now we can require index.js and save the exports inside a namespace called myFunctions.
myFunctions = require('../index.js');

HTTP가 아닌 백그라운드 함수 테스트

HTTP가 아닌 함수를 테스트하는 절차는 다음과 같습니다.

  1. test.wrap 메서드로 테스트할 함수를 래핑합니다.
  2. 테스트 데이터를 구성합니다.
  3. 구성한 테스트 데이터 및 지정할 이벤트 컨텍스트 필드를 포함해 래핑한 함수를 호출합니다.
  4. 동작에 대한 어설션을 만듭니다.

먼저 테스트 할 함수를 래핑합니다. functions/index.js에 makeUppercase라는 테스트할 함수가 있다고 가정해보겠습니다. functions/test/index.test.js에 다음 코드를 작성합니다.

const myFunctions = require('../index.js');
const wrpped = test.wrap(myFunctions.makeUppercase);

wrapped는 호출 시 makeUppercase를 호출하는 함수입니다. wrapped는 매개변수 두 개를 사용합니다.

  1. data(필수사항): makeUppercase로 보낼 데이터입니다. 작성한 함수 핸들러는 전송되는 첫번째 매개변수에 직접적으로 해당합니다. firebase-functions-test가 커스텀 데이터나 예시 데이터 구성을 위한 메서드를 제공합니다.
  1. eventContextOptions(선택사항): 지정할 이벤트 컨텍스트의 필드입니다. 이벤트 컨텍스트는 작성한 함수 핸들러로 전송되는 두 번째 매개변수입니다. wrapped를 호출할 때 eventContextOptions 매개변수를 포함하지 않아도 알맞은 필드로 이벤트 컨텍스트가 생성됩니다. 여기에서 지정하면 생성된 필드 중 일부를 재정의할 수 있습니다. 재정의할 필드만 포함해야 한다는 점에 유의하세요. 재정의하지 않은 모든 필드는 생성됩니다.

0개의 댓글