The happiest moment in the development of any application is that first “Hello world” you managed to print. I am pretty certain that the popularity of some technologies and programming languages, in particular, is inversely correlated to the amount of time it takes to get to that “hello world!”.
Cloud functions are not an exception; they allow you to be very fast by cutting the time it takes to set up:
So you get your dose of nerd dopamine much faster, but then you suddenly realize that the same rules apply. Yes, those boring rules — every code must be tested and automatically deployed if you want to work with it for a time period longer than one weekend. So how do we do it with cloud functions?
Google provides a pretty neat explanation of how they see different types of tests. But when you start reading the code, you just ask yourself, is it not just the same thing? So let me give an easy (not an RTFM) explanation:
Some academics might disagree with my definitions. There is a fair amount of art you need to master to do testing efficiently. For example, in integration tests, you might want to relax some stubs, but not all, or deploy them already to some staging environment. But roll with me on this one.
If you are testing your functions through UI on GCP console, just stop. Ok? Google provides an excellent framework to run cloud functions locally — functions-framework. You must try to run things locally before pushing them anywhere.
TLDR; To avoid all the setup steps, you can just clone or fork my boilerplate repository for GCP functions. Work in progress, looking forward to your pull request.
After you initialized your project, install functions-framework:
Add your first functions to index.js. In our example, we have two basic function types — HTTP and background function. They both do the same thing — get the name and print, e.g., ‘Hello Mike’ or ‘Hello World’, when the parameter is not specified. HTTP function replies via HTTP response and background function write it back to a PubSub topic.
Ignore the getDataFromEvent method; for now, it will become apparent later why it is needed.
In your package.json file, you can now specify run-script commands like this:
One last thing, since you want to test things locally, you want to have PubSub locally. You say impossible? GCloud CLI makes it possible. The following two commands will start the emulator and initialize environment variables. From that point on, every Google Cloud library will talk to your local instance of PubSub.
For tests, we will be using the Jest testing framework. You are more than welcome to look into Mocha.
For this type of functions, unit testing is pretty straightforward:
I would strongly recommend using the jest-express library for consistency. A happy path unit test for the code above could look like this:
We try to pass GUID as a name, so we can catch it later. The following checks are performed: a) was the send function called at all, i.e. did it send a response, b) was it called with the GUID we passed. You can also add a test to verify that it returned 200. For not happy path testing, checking HTTP response code becomes more important
This type is much more challenging to test, because
Jest provides the mechanism of manual mocks. You can put a folder under __mocks__ to match the library you want to mock, and it will do the rest for you. In our case folder structure would be:
To test the example above, the mock is super slim. We just need one function to test so we will mock just that:
The unit test itself is a bit more involved because we have to feed the entire request and also encode it along the way, but that way, we do not have to call any service:
Before I started writing this article, I wanted to cover all types of tests at once. Still, while writing, I have realized that it gets more nuanced the deeper we go in testing, especially around integration tests, so I decided to put it into a separate article with more detailed explanations. Stay tuned!
Sprechen wir darüber!