Search code examples
pythonunit-testingintegration-testingpython-unittest

Python unittest mocking not working as expected


I got this project structure:

my_project 
├── __init__.py
├── app.py
├── helpers
│   └── __init__.py
└── tests
    ├── __init__.py
    ├── integration
    │   ├── __init__.py
    │   └── test_app.py
    └── unit
        ├── __init__.py
        └── test_helpers.py

So far, unit testing for helpers hasn't been complicated, i'd patch 3rd parties and some functions within helpers.

The integration testing in tests/integration/test_app.py is being a bit of a blocking point because the patching isn't doing what i need it do to. For example, I got a method like this:

helpers/init.py:

def compute_completeness_metric(
        vendor,
        product,
        fields,
        endpoint):
    body = {"vendor": vendor, "product": product, "fields": fields}
    response_json = requests.post(
        "http://example.com", json=body)
    if response_json.status_code != 200:
        response_json = "Can't compute"
    else:
        response_json = response_json.json()
    return response_json

Now, in app.py, I call it the following way:

from helpers import compute_completeness_metric
def main(req: func.HttpRequest) -> func.HttpResponse:
    final_results = {}
    final_results = compute_completeness_metric(vendor, product, fields, endpoint)
...

And when testing, I try to patch it the following way:

    @patch('data_quality.helpers.compute_completeness_metric')
    def test_app(self, mock_compute_completeness_metric):
      mock_compute_completeness_metric.return_value = "blablabla"

But the mocked methods do not return what they're supposed to return, instead execute themselves as if they weren't mocked.

Am I missing something? Should I be mocking the methods within get_rule_data_models() ?

TIA!


Solution

  • The way you mock a function depends on the way it is declared or imported.

    If you used

    import helpers
    ...
         final_results = helpers.compute_completeness_metric(vendor, product, fields, endpoint)
    

    Then mocking with @patch('data_quality.helpers.compute_completeness_metric') would be fine

    But here you use:

    from helpers import compute_completeness_metric
    ...
        final_results = compute_completeness_metric(vendor, product, fields, endpoint)
    

    That means that in app.py you no longer use the symbol from the helpers module but a local symbol that points to where helpers.compute_completeness_metric pointed at import time. That means that you have to patch the symbol in the app module:

    @patch('data_quality.app.compute_completeness_metric')
    def test_app(self, mock_compute_completeness_metric):
      mock_compute_completeness_metric.return_value = "blablabla"