Home > Back-end >  Mocking an object inside index function in a route
Mocking an object inside index function in a route

Time:10-12

I am testing a function in the module match_view.py (below)

from dbaccess.repository import bulk_update_zingr_id, bulk_insert_ingredients_matching_table
from services.matching_ingr_zingr import ingr_zing_match_mult_search
from services.FileStorage import dumpModel
from flask import Blueprint, request
from datetime import date
import pandas as pd
import logging
import time

match = Blueprint("match", __name__)

@match.route("/", methods=['GET', 'POST'], strict_slashes=False) 
def index():
    if request.method == 'POST':

        logging.warning(""" RODAR O ELASTICSEARCH PARA INGREDIENTES ZAPLY ANTES DE RODAR O MATCHING""")

        ingredients_list = request.get_json()

        start = time.time()

        results, resume, payload = ingr_zing_match_mult_search(ingredients_list)
        
        today = date.today().strftime("%b-%d-%Y")

        dumpModel(results.to_dict(), f"result_table_{today}")
        dumpModel(resume.to_dict(), f"resume_table_{today}")

        bulk_update_zingr_id(payload)
        bulk_insert_ingredients_matching_table(resume)

        tot_row = len(list(set(resume['Raw_Ingred'])))

        end = time.time()
        tempo = round(((end - start)), 4)
        logging.warning(f"O tempo para processamento da request foi de: {tempo/60} minutos, {tempo/tot_row} segundos por item para {tot_row} ingredientes.")
        
        return payload 
    else:
        return "Use o método POST para processar os dados."

I tried in two ways.

1º Try mocking the path 'src.api.matching.match_view.ingr_zing_match_mult_search' to the function (run but do not mock).

test_00_api.py

import pytest
import sys, os

sys.path.append(os.path.realpath(os.path.dirname(__file__) "/src"))

def test_match_view_post_retorno_correto(client, mocker):

    result_expected = {'sal a gosto': 594, '1 cebola picada': 44}
    
    mocker.patch('src.api.matching.match_view.ingr_zing_match_mult_search',
                  return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

    RESOURCE_URL = "/match"
    resp = client.post(RESOURCE_URL, json=['sal a gosto', '1 cebola picada'])


    assert resp.status_code == 200
    assert result_expected in resp.get_data(as_text=True)

2º Try mocking the path 'src.api.matching.index.match_view.ingr_zing_match_mult_search' but raisse an error (AttributeError: <function index at 0x000001A600339DC8> does not have the attribute 'ingr_zing_match_mult_search').

test_00_api.py

import pytest
import sys, os

sys.path.append(os.path.realpath(os.path.dirname(__file__) "/src"))

def test_match_view_post_retorno_correto(client, mocker):

    result_expected = {'sal a gosto': 594, '1 cebola picada': 44}
    
    mocker.patch('src.api.matching.match_view.index.ingr_zing_match_mult_search',
                  return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

    RESOURCE_URL = "/match"
    resp = client.post(RESOURCE_URL, json=['sal a gosto', '1 cebola picada'])

    assert resp.status_code == 200
    assert result_expected in resp.get_data(as_text=True)

My project structure is:

src
|--- api
|    |--- matching
|         |--- match_view.py
|
tests
|--- test_src
     |--- test_00_api.py

How is the right way to mocker de function ingr_zing_match_mult_search()?

@Macintosh_89 here is my last try and error:

from src.api.matching import match_view
import pytest
import sys, os

sys.path.append(os.path.realpath(os.path.dirname(__file__) "/src"))

def test_match_view_post_retorno_correto(mocker, client):

    result_expected = {'sal a gosto': 594, '1 cebola picada': 44}

    mocker.patch('src.api.matching.match_view.ingr_match_mult_search',
                 return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

    RESOURCE_URL = "/match"
    resp = client.post(RESOURCE_URL, json=['sal a gosto', '1 cebola picada'])

    assert resp.status_code == 200
    assert result_expected in resp.get_data(as_text=True)

ERRO:

======================================================================================================= FAILURES ======================================================================================================= 
_________________________________________________________________________________________ test_match_view_post_retorno_correto _________________________________________________________________________________________ 

mocker = <pytest_mock.plugin.MockerFixture object at 0x0000017527CB7908>, client = <FlaskClient <Flask 'src.app'>>

    def test_match_view_post_retorno_correto(mocker, client):

        result_expected = {'sal a gosto': 594, '1 cebola picada': 44}

        mocker.patch('src.api.matching.match_view.ingr_match_mult_search',
>                    return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

tests\test_src\test_00_api.py:64: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  
..\..\..\miniconda3\envs\match_prod_ingr\lib\site-packages\pytest_mock\plugin.py:402: in __call__
    **kwargs
..\..\..\miniconda3\envs\match_prod_ingr\lib\site-packages\pytest_mock\plugin.py:201: in _start_patch
    mocked = p.start()  # type: unittest.mock.MagicMock
..\..\..\miniconda3\envs\match_prod_ingr\lib\unittest\mock.py:1442: in start
    result = self.__enter__()
..\..\..\miniconda3\envs\match_prod_ingr\lib\unittest\mock.py:1307: in __enter__
    original, local = self.get_original()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  

self = <unittest.mock._patch object at 0x0000017527C8A1C8>

    def get_original(self):
        target = self.getter()
        name = self.attribute

        original = DEFAULT
        local = False

        try:
            original = target.__dict__[name]
        except (AttributeError, KeyError):
            original = getattr(target, name, DEFAULT)
        else:
            local = True

        if name in _builtins and isinstance(target, ModuleType):
            self.create = True

        if not self.create and original is DEFAULT:
            raise AttributeError(
>               "%s does not have the attribute %r" % (target, name)
            )
E           AttributeError: <module 'src.api.matching.match_view' from 'C:\\Users\\zaply\\Desktop\\Zaply\\matching\\src\\api\\matching\\match_view.py'> does not have the attribute 'ingr_match_mult_search'

..\..\..\miniconda3\envs\match_prod_ingr\lib\unittest\mock.py:1281: AttributeError
=============================================================================================== short test summary info ================================================================================================ 
FAILED tests/test_src/test_00_api.py::test_match_view_post_retorno_correto - AttributeError: <module 'src.api.matching.match_view' from 'C:\\Users\\zaply\\Desktop\\Zaply\\matching\\src\\api\\matching\\match_view.py...================================================================================================== 1 failed in 0.59s =================================================================================================== 

4º Try test (run but do not mock execute the ingr_zing_match_mult_search() function instead)

from src.api.matching import match_view
import pytest
import sys, os

def test_match_view_post_retorno_correto(mocker, client):

    result_expected = {'sal a gosto': 594, '1 cebola picada': 44}

    mocker.patch('src.api.matching.match_view.ingr_zing_match_mult_search',
                 return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

    RESOURCE_URL = "/match"
    resp = client.post(RESOURCE_URL, json=['sal a gosto', '1 cebola picada'])

    assert resp.status_code == 200
    assert result_expected in resp.get_data(as_text=True)

CodePudding user response:

I think you need to import the function itself into the test file. Try:

from src.api.matching.match_view import ingr_zing_match_mult_search

And then to patch that function:

    mocker.patch('src.api.matching.match_view.ingr_zing_match_mult_search',
                 return_value=[[], [], {'sal a gosto': 594, '1 cebola picada': 44}])

See here for more.

CodePudding user response:

After many. many attempts I finally find a solution (I will past the solution at the end of this answer). Basically I manage to run the test, I imported the index() function ti perform a unittest in the POST method. For that, using context manager, I activate the test_request_context. So I manage to mock the results inside de index() (all functions were tested before). Then the test run and cover all lines needed. I really do not know if this is the best way to perform the unit test, and I beliave that this is not the Pythonic way to perform this, but work and is fine (after 4 days trying). If someone read my test and can explain me a better way to do this, or the pythonic ways I will glad to kown and learn, so please feel confortable to comments and discuss my solution.

test_00_api.py

from src.api.matching.match_view import index
import pandas as pd
import pytest
import sys, os

def test_match_view_post_retorno_correto(client, mocker):

    from flask import Flask
    app = Flask(__name__)

    resume = pd.DataFrame()
    results = pd.DataFrame()
    
    resume['Raw_Ingred'] = ['sal a gosto', '1 cebola picada']
    results['Raw_Ingred'] = ['sal a gosto', '1 cebola picada']
    payload = {'sal a gosto': 594, '1 cebola picada': 44}

    result_expected = {'sal a gosto': 594, '1 cebola picada': 44}

    with app.test_request_context("/match",
                                  method="POST",
                                  json=['sal a gosto', '1 cebola picada']):


        mocker.patch('src.api.matching.match_view.ingr_zing_match_mult_search',
                     return_value= [results, resume, payload])
        
        mocker.patch('src.api.matching.match_view.dumpModel', return_value=None)

        mocker.patch('src.api.matching.match_view.bulk_update_zingr_id',
                    return_value=[])
        
        mocker.patch('src.api.matching.match_view.bulk_insert_ingredients_matching_table',
                    return_value=[])

        result = index()

    assert result == result_expected
  • Related