This guide covers best practices for testing and deploying Cloud Functions, discusses the types of tests you should use, and provides some instructions for example testing scenarios. This guide also has information on automatically running your tests and optionally redeploying your functions using a Continuous Integration and Deployment (CI/CD) platform such as Cloud Build.
Before you begin
Before starting this guide, set up your environment.
Node.js
- Go to the Node.js setup guide
- Optionally, install the Node.js Emulator.
Python (Beta)
- Go to the Python setup guide
-
Install
pytest
.pip install --upgrade pytest
Go (Beta)
Frameworks
Node.js
The examples in this guide use AVA as a test framework to run tests and Sinon as a mocking framework to mock external dependencies.An external dependency is a dependency that your function relies on that isn't a part of your function's code. Common examples of external dependencies are other Google Cloud Platform services and libraries installed using package managers such as npm.
Python (Beta)
The examples in this guide use Pytest as a test framework to run tests and unittest as a mocking framework to mock external dependencies.
An external dependency is a dependency that your function relies on that isn't a part of your function's code. Common examples of external dependencies are other Google Cloud Platform services and libraries installed using package managers such as pip.
Go (Beta)
The examples in this guide use the standard librarytesting
package to run tests. However,
the system tests have external dependencies.
An external dependency is a dependency that your function relies on that isn't a part of your function's code. Common examples of external dependencies are other Google Cloud Platform services and other packages you've downloaded.
Types of tests
There are three types of tests that you can use when working with Cloud Functions, each of which tests a different aspect of your code. They are listed below, from least to most thorough:
- Unit tests
- Integration tests
- System tests
In general, more thorough tests take more time to complete. This document discusses these test types in detail, as well as how to strike a balance between speed and thoroughness.
Unit tests
Unit tests are narrowly-scoped tests for small, specific parts of your code. These tests are good for quickly verifying assumptions made during the development process, such as handling edge cases and input validation.
By design, unit tests do not test integration with any external dependencies, such as Cloud Functions itself or other Google Cloud Platform components. You can use your mocking framework to create mock versions of external dependencies.
For HTTP functions, tests should mock the wrapping HTTP framework. Confirm the function's behavior by combining testing and mocking frameworks and comparing your function's results to expected values.
Unit tests cannot detect changes in external dependencies. If these dependencies change, both the tested code and your mocks must be updated.
Integration tests
Integration tests validate interaction between parts of your code, and typically take a moderate amount of time to complete. For example, in Cloud Functions, integration tests can be used to test a function's usage of other GCP services such as Cloud Datastore or Cloud Vision.
The primary difference between unit tests and integration tests for Cloud Functions is that integration tests involve less mocking than unit tests. Integration tests should trigger and respond to Cloud events such as HTTP requests, Cloud Pub/Sub messages, or Storage object changes.
You can run integration tests locally using a shim. Validate function behavior by confirming the expected result, given specific inputs.
System tests
System tests are more complex tests that validate the behavior of your Cloud Function across multiple GCP components in an isolated test environment.
Deploy your Cloud Function to a test environment and test its functionality by triggering the appropriate events. Validate your function by reading the logs or checking for the desired behavior.
You should isolate your development, testing, and production environments. One way to achieve this is to use a separate GCP project for each step.
You should also assign system test resources globally unique names to prevent concurrent tests from interfering with each other. You can do this by programmatically creating and deleting the required resources before and after the test run.
Example testing scenarios
The scenarios below cover the different ways of triggering Cloud Functions. The structure of a function's tests depends heavily on which GCP resources a function uses. In turn, a function's resource use depends on how that function is triggered.
HTTP-triggered functions
Unlike tests for other types of functions, system and integration tests for HTTP-triggered functions are similar in structure, but most HTTP function unit tests have a different structure.
This overlap between system and integration tests is shown in the following example of an HTTP-triggered function:
Node.js
Python (Beta)
Go (Beta)
Unit tests
These tests act as unit tests for the HTTP-triggered function above.
Use the following command to run the unit tests:
Node.js
ava test/sample.unit.http.test.js
Python (Beta)
pytest sample_http_test.py
Go (Beta)
go test -v ./hello_http_test.go
Integration tests
These tests act as integration tests for the function above:
Node.js
Use the following file as a shim:
Node.js
To run integration tests for HTTP functions, use the following command:
Node.js
export PORT=8010 export BASE_URL=http://localhost:8010/YOUR_GCP_PROJECT_ID/YOUR_GCF_REGION ava test/sample.integration.http.test.js
where:
YOUR_GCP_PROJECT_ID
is your GCP project ID.YOUR_GCF_REGION
is your Cloud Functions region.BASE_URL
is an environment variable that specifies the URL where the function can be reached. Environment variables let you specify values available only in your local test environment. This allows you to avoid hardcoding these values into your code.
System tests
These tests act as system tests for the function above:
Node.js
Note that the system tests are identical to the function's integration tests.Python (Beta)
Go (Beta)
To run system tests for HTTP functions, deploy your functions with the following command:
Node.js 6
gcloud functions deploy helloHttp --runtime nodejs6
Node.js 8 (Beta)
gcloud functions deploy helloHttp --runtime nodejs8
Python (Beta)
gcloud functions deploy hello_http --runtime python37
Go (Beta)
gcloud functions deploy HelloHTTP --runtime go111
Use the following commands to test your deployed HTTP function:
Node.js
Note that the primary difference between system tests and integration tests for HTTP Cloud Functions is the URL where the function can be reached.export BASE_URL=https://YOUR_GCF_REGION-YOUR_GCP_PROJECT_ID.cloudfunctions.net/ ava test/sample.system.http.test.js
Python (Beta)
export BASE_URL=https://YOUR_GCF_REGION-YOUR_GCP_PROJECT_ID.cloudfunctions.net/ pytest sample_http_test_system.py
Go (Beta)
export BASE_URL=https://YOUR_GCF_REGION-YOUR_GCP_PROJECT_ID.cloudfunctions.net/ go test -v ./hello_http_system_test.go
where:
YOUR_GCF_REGION
is your Cloud Functions region.YOUR_GCP_PROJECT_ID
is your GCP project ID.
Pub/Sub-triggered functions
Pub/Sub-triggered function tests are structured differently depending on where the tested function resides.
Here is an example of a Pub/Sub-triggered function:
Node.js 6
Node.js 8 (Beta)
Python (Beta)
Go (Beta)
Unit tests
These tests act as unit tests for the Pub/Sub-triggered function above:
Node.js 6
Node.js 8 (Beta)
Python (Beta)
Go (Beta)
Use the following command to run the unit tests:
Node.js
ava test/sample.unit.pubsub.test.js
Python (Beta)
pytest sample_pubsub_test.py
Go (Beta)
go test -v ./hello_pubsub_test.go
Integration tests
These tests act as integration tests for the Pub/Sub-triggered function above:
Node.js
Use the following file as a shim:
Node.js
To run the integration tests for this function, complete the following steps:
Node.js
Optionally, if you haven't set the topic and subscription in your shim file, set the following environment variables:
export TOPIC=YOUR_TOPIC export SUBSCRIPTION=YOUR_SUBSCRIPTION
where:
-
YOUR_TOPIC
is name of the Cloud Pub/Sub topic you want your functions to subscribe to. -
YOUR_SUBSCRIPTION
is your Cloud Pub/Sub subscription.
-
To run the test, use the following command:
ava test/sample.integration.pubsub.test.js
System tests
These tests act as system tests for this function:
Node.js
Python (Beta)
Go (Beta)
To run the system tests:
In your GCP project, select a Cloud Pub/Sub topic to subscribe to. If you provide the name of a Cloud Pub/Sub topic that does not exist, it is created automatically.
Next, deploy your functions using the following command:
Node.js 6
gcloud functions deploy helloPubSub --runtime nodejs6 --trigger-topic YOUR_PUBSUB_TOPIC
Node.js 8 (Beta)
gcloud functions deploy helloPubSub --runtime nodejs8 --trigger-topic YOUR_PUBSUB_TOPIC
Python (Beta)
gcloud functions deploy hello_pubsub --runtime python37 --trigger-topic YOUR_PUBSUB_TOPIC
Go (Beta)
gcloud functions deploy HelloPubSub --runtime go111 --trigger-topic YOUR_PUBSUB_TOPIC
where
YOUR_PUBSUB_TOPIC
is the name of the Cloud Pub/Sub topic you want your functions to subscribe to.Run the system tests with the following command:
Node.js
export FUNCTIONS_TOPIC=YOUR_PUBSUB_TOPIC ava test/sample.system.pubsub.test.js
Python (Beta)
export FUNCTIONS_TOPIC=YOUR_PUBSUB_TOPIC pytest sample_pubsub_test_system.py
Go (Beta)
export FUNCTIONS_TOPIC=YOUR_PUBSUB_TOPIC go test -v ./hello_pubsub_system_test.go
where
YOUR_PUBSUB_TOPIC
is the name of the Cloud Pub/Sub topic you want your functions to subscribe to.
Storage-triggered functions
Tests for storage-triggered functions are similar in structure to their Cloud Pub/Sub-triggered counterparts. Like Cloud Pub/Sub-triggered function tests, storage-triggered function tests are structured differently depending on where the tested function is hosted.
Here is an example of a storage-triggered function:
Node.js 6
Node.js 8 (Beta)
Python (Beta)
Go (Beta)
Unit tests
These are the unit tests for the storage-triggered function above:
Node.js 6
Node.js 8 (Beta)
Python (Beta)
Go (Beta)
Use the following command to run the unit tests:
Node.js
ava test/sample.unit.storage.test.js
Python (Beta)
pytest sample_storage_test.py
Go (Beta)
go test -v ./hello_cloud_storage_test.go
Integration tests
These are the integration tests for the storage-triggered function above:
Node.js
Use the following file as a shim:
Node.js
Use the following command to run the integration tests:
Node.js
Optionally, if you haven't set the topic and subscription in your shim file, set the following environment variables:
export TOPIC=YOUR_TOPIC export SUBSCRIPTION=YOUR_SUBSCRIPTION
where:
-
YOUR_TOPIC
is name of the Cloud Pub/Sub topic you want your functions to subscribe to. -
YOUR_SUBSCRIPTION
is your Cloud Pub/Sub subscription.
-
To run the test, use the following command:
ava test/sample.integration.storage.test.js
System tests
These are the system tests for the storage-triggered function above:
Node.js
Python (Beta)
Go (Beta)
Use the following command to deploy your function:
Node.js 6
gcloud functions deploy helloGCS --runtime nodejs6 --trigger-bucket YOUR_GCS_BUCKET_NAME
Node.js 8 (Beta)
gcloud functions deploy helloGCS --runtime nodejs8 --trigger-bucket YOUR_GCS_BUCKET_NAME
Python (Beta)
gcloud functions deploy hello_gcs --runtime python37 --trigger-bucket YOUR_GCS_BUCKET_NAME
Go (Beta)
gcloud functions deploy HelloGCS --runtime go111 --trigger-bucket YOUR_GCS_BUCKET_NAME
where YOUR_GCS_BUCKET_NAME
is the Cloud Storage bucket
you want to monitor. Note that this must reference a bucket that exists in the
same GCP project that the function is deployed to.
Use the following commands to run the system tests:
Node.js
export BUCKET_NAME=YOUR_GCS_BUCKET_NAME ava test/sample.system.storage.test.js
Python (Beta)
export BUCKET_NAME=YOUR_GCS_BUCKET_NAME pytest sample_storage_test_system.py
Go (Beta)
export BUCKET_NAME=YOUR_GCS_BUCKET_NAME go test -v ./hello_cloud_storage_system_test.go
Continuous testing and deployment
As you develop your function, you can run unit tests, integration tests, and system tests to ensure that your functions work both locally and in a test environment on GCP.
Once you finish developing locally, you can configure a continuous integration and deployment (CI/CD) platform such as Cloud Build to run your existing Cloud Functions tests on an ongoing basis. Continuous testing helps ensure that your code continues to work as intended and that your dependencies remain up-to-date. As Cloud Functions are not updated automatically, you can also configure continuous integration platforms (including Cloud Build) to automatically test and redeploy your functions from a source repository such as GitHub, Bitbucket, or Cloud Source Repositories.
Follow the instructions in the
Automating Builds using Build Triggers
guide using the cloudbuild.yaml
build config file below to configure
Cloud Build to automatically test and deploy your function. Replace
[YOUR_FUNCTION_NAME]
with the name of your Cloud Functions and
[YOUR_FUNCTION_TRIGGER]
with the appropriate
trigger value.
Node.js
If Cloud Build doesn't suit your needs, see this list of continuous integration platforms.
Granting permissions to run builds and deployments
If you are using Cloud Build, you need to grant permissions to the Cloud Build service account.
For example:
- To deploy Cloud Functions, you might want to assign the Cloud
Functions Developer role to the Cloud Build service account
(
PROJECT_NUMBER@cloudbuild.gserviceaccount.com
). - If you use the Cloud Functions Developer role, you also need to grant the
Cloud Functions Runtime service account
(
PROJECT_ID@appspot.gserviceaccount.com
) the IAM Service Account User role.