0

I'm getting started writing Google Cloud http Functions using Python and I would like to include unit tests. My function only responds to POST requests so the basic outline of my function is:

def entry_point(request):
    if request.method == 'POST':
        # do something
    else:
        # throw error or similar

I want to write a simple unit test to ensure that if the function receives a GET request the response has a 405 status.

Hence in my unit test I need to pass in a value for the request parameter:

def test_call(self):
    req = #need a way of constructing a request

    response = entry_point(req)
    assert response.status  == 405 # or something like this

Basically I need to construct a request then check that the response status is what I expect it to be. I've googled around and found loads of pages that talk about mocking and all sorts of stuff that I frankly don't understand (I'm not a crash hot developer) so I'm hoping someone can help me with an idiot's guide of doing what I need to do.

I did find this: https://cloud.google.com/functions/docs/bestpractices/testing#unit_tests_2:

from unittest.mock import Mock

import main


def test_print_name():
    name = 'test'
    data = {'name': name}
    req = Mock(get_json=Mock(return_value=data), args=data)

    # Call tested function
    assert main.hello_http(req) == 'Hello {}!'.format(name)


def test_print_hello_world():
    data = {}
    req = Mock(get_json=Mock(return_value=data), args=data)

    # Call tested function
    assert main.hello_http(req) == 'Hello World!'

which kinda helped but it doesn't explain how I can specify the request method (i.e. GET, POST etc...).

jamiet
  • 10,501
  • 14
  • 80
  • 159
  • I have looked into the "unittest.mock" documentation and didn't found a way to mock the request context like an HTTP call, however I did found other ways to test this kind of context on other SO questions, did you try did one? -- > https://stackoverflow.com/a/17377101/7806223 or this one? --> https://stackoverflow.com/a/23914464/7806223 – Mayeru Jul 12 '19 at 14:52
  • Thanks, though I don't think `test_client()` will help. My code runs inside a Google Cloud Platform (GCP) Function which inherently uses Flask to handle the external request, my code merely handles the request object that gets passed to it from Google Cloud Platform. In my code I don't even make direct use of Flask (there is no `import flask` or similar), I don't stand up an HTTP endpoint, GCP wraps my code with Flask and does that for me. `test_client()` appears to expect that the code I'm testing is a Flask app - that is not the case. – jamiet Jul 12 '19 at 18:49
  • Same thing goes for the requests library. It assumes the code it is testing stands up an HTTP endpoint. The code I want to test does not to do that. – jamiet Jul 12 '19 at 19:00

2 Answers2

4

It is probably late to also comment on this one, but I was going through the same quest. How to REALLY unit test a cloud function without mocks and/or Flask test client. For the records, at the Google Cloud Platform Python Docs Samples, it is explained how to use Flask test_request_context() functionality with some examples to achieve this (without having to create Request object by hand).

André X
  • 58
  • 1
  • 2
  • googled myself here 3 years after asking the original question and found this excellent answer. Thank you Andre, marked as an answer. – jamiet Oct 10 '22 at 11:23
2

Just dawned on me that I was rather over-thinking this somewhat. For the purposes of testing my code doesn't actually require a real Flask request passed to it, it merely requires an object that has the attributes my code refers to. For me, this will do:

import unittest
from main import entry_point


class Request:
    def __init__(self, method):
        self.method = method

class MyTestClass(unittest.TestCase):
    def test_call_with_request(self):
        request = Request("GET")
        response = entry_point(request)
        assert response.status_code == 405

jamiet
  • 10,501
  • 14
  • 80
  • 159