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