为什么模拟补丁仅在 运行 特定测试而不是整个测试套件时有效?
Why does mock patch only work when running specific test and not whole test suite?
我将 Django 和 Pytest 专门用于 运行 测试套件,并尝试测试当用户访问网站时特定表单是否显示预期数据(集成测试)。
这个特定的视图使用了一个存储过程,我正在嘲笑它,因为测试永远无法访问它。
我的测试代码是这样的:
#test_integrations.py
from my_app.tests.data_setup import setup_data, setup_sb7_data
from unittest.mock import patch
...
# Setup to use a non-headless browser so we can see whats happening for debugging
@pytest.mark.usefixtures("standard_browser")
class SeniorPageTestCase(StaticLiveServerTestCase):
"""
These tests surround the senior form
"""
@classmethod
def setUpClass(cls):
cls.host = socket.gethostbyname(socket.gethostname())
super(SeniorPageTestCase, cls).setUpClass()
def setUp(self):
# setup the dummy data - this works fine
basic_setup(self)
# setup the 'results'
self.sb7_mock_data = setup_sb7_data(self)
@patch("my_app.utils.get_employee_sb7_data")
def test_senior_form_displays(self, mock_sb7_get):
# login the dummy user we created
login_user(self, "futureuser")
# setup the results
mock_sb7_get.return_value = self.sb7_mock_data
# hit the page for the form
self.browser.get(self.live_server_url + "/my_app/senior")
form_id = "SeniorForm"
# assert that the form displays on the page
self.assertTrue(self.browser.find_element_by_id(form_id))
# utils.py
from django.conf import settings
from django.db import connections
def get_employee_sb7_data(db_name, user_number, window):
"""
Executes the stored procedure for getting employee data
Args:
user_number: Takes the user_number
db (db connection): Takes a string of the DB to connect to
Returns:
"""
cursor = connections[db_name].cursor()
cursor.execute(
'exec sp_sb7 %s, "%s"' % (user_number, window.senior_close)
)
columns = [col[0] for col in cursor.description]
results = [dict(zip(columns, row)) for row in cursor.fetchall()]
return results
# views.py
from myapp.utils import (
get_employee_sb7_data,
)
...
###### Senior ######
@login_required
@group_required("user_senior")
def senior(request):
# Additional Logic / Getting Other Models here
# Execute stored procedure to get data for user
user_number = request.user.user_no
results = get_employee_sb7_data("production_db", user_number, window)
if not results:
return render(request, "users/senior_not_required.html")
# Additional view stuff
return render(
request,
"users/senior.html",
{
"data": data,
"form": form,
"results": results,
},
)
如果我运行这个测试本身:
pytest my_app/tests/test_integrations.py::SeniorPageTestCase
测试顺利通过。浏览器显示 - 表单显示了我们预期的虚拟数据,一切正常。
但是,如果我 运行:
pytest my_app
所有其他测试 运行 并通过 - 但此 class 中的所有测试都失败了,因为它没有修补功能。
它尝试调用实际的存储过程(因为它还没有在生产服务器上而失败)但失败了。
为什么当我专门调用那个 TestCase 时它会正确打补丁 - 但当我只是 运行 pytest
在应用程序或项目级别时却没有正确打补丁?
我很茫然,不知道如何很好地调试它。感谢任何帮助
所以发生的事情是你的观点在你打补丁之前被导入。
让我们先看看工作案例:
- pytest 导入 test_integrations 文件
- 测试已执行,补丁装饰器的内部函数为运行
- 还没有导入实用程序,因此补丁导入并替换了函数
- 测试体被执行,传递一个url给测试客户端
- 测试客户端导入解析器,然后导入视图,视图导入实用程序。
- 由于实用程序已经修补,一切正常
如果另一个测试用例 运行 首先,它也导入相同的视图,那么导入成功并且补丁不能替换导入。
您的解决方案是引用相同的符号。所以在 test_integrations.py
:
@patch("myapp.views.get_employee_sb7_data")
我将 Django 和 Pytest 专门用于 运行 测试套件,并尝试测试当用户访问网站时特定表单是否显示预期数据(集成测试)。
这个特定的视图使用了一个存储过程,我正在嘲笑它,因为测试永远无法访问它。
我的测试代码是这样的:
#test_integrations.py
from my_app.tests.data_setup import setup_data, setup_sb7_data
from unittest.mock import patch
...
# Setup to use a non-headless browser so we can see whats happening for debugging
@pytest.mark.usefixtures("standard_browser")
class SeniorPageTestCase(StaticLiveServerTestCase):
"""
These tests surround the senior form
"""
@classmethod
def setUpClass(cls):
cls.host = socket.gethostbyname(socket.gethostname())
super(SeniorPageTestCase, cls).setUpClass()
def setUp(self):
# setup the dummy data - this works fine
basic_setup(self)
# setup the 'results'
self.sb7_mock_data = setup_sb7_data(self)
@patch("my_app.utils.get_employee_sb7_data")
def test_senior_form_displays(self, mock_sb7_get):
# login the dummy user we created
login_user(self, "futureuser")
# setup the results
mock_sb7_get.return_value = self.sb7_mock_data
# hit the page for the form
self.browser.get(self.live_server_url + "/my_app/senior")
form_id = "SeniorForm"
# assert that the form displays on the page
self.assertTrue(self.browser.find_element_by_id(form_id))
# utils.py
from django.conf import settings
from django.db import connections
def get_employee_sb7_data(db_name, user_number, window):
"""
Executes the stored procedure for getting employee data
Args:
user_number: Takes the user_number
db (db connection): Takes a string of the DB to connect to
Returns:
"""
cursor = connections[db_name].cursor()
cursor.execute(
'exec sp_sb7 %s, "%s"' % (user_number, window.senior_close)
)
columns = [col[0] for col in cursor.description]
results = [dict(zip(columns, row)) for row in cursor.fetchall()]
return results
# views.py
from myapp.utils import (
get_employee_sb7_data,
)
...
###### Senior ######
@login_required
@group_required("user_senior")
def senior(request):
# Additional Logic / Getting Other Models here
# Execute stored procedure to get data for user
user_number = request.user.user_no
results = get_employee_sb7_data("production_db", user_number, window)
if not results:
return render(request, "users/senior_not_required.html")
# Additional view stuff
return render(
request,
"users/senior.html",
{
"data": data,
"form": form,
"results": results,
},
)
如果我运行这个测试本身:
pytest my_app/tests/test_integrations.py::SeniorPageTestCase
测试顺利通过。浏览器显示 - 表单显示了我们预期的虚拟数据,一切正常。
但是,如果我 运行:
pytest my_app
所有其他测试 运行 并通过 - 但此 class 中的所有测试都失败了,因为它没有修补功能。
它尝试调用实际的存储过程(因为它还没有在生产服务器上而失败)但失败了。
为什么当我专门调用那个 TestCase 时它会正确打补丁 - 但当我只是 运行 pytest
在应用程序或项目级别时却没有正确打补丁?
我很茫然,不知道如何很好地调试它。感谢任何帮助
所以发生的事情是你的观点在你打补丁之前被导入。
让我们先看看工作案例:
- pytest 导入 test_integrations 文件
- 测试已执行,补丁装饰器的内部函数为运行
- 还没有导入实用程序,因此补丁导入并替换了函数
- 测试体被执行,传递一个url给测试客户端
- 测试客户端导入解析器,然后导入视图,视图导入实用程序。
- 由于实用程序已经修补,一切正常
如果另一个测试用例 运行 首先,它也导入相同的视图,那么导入成功并且补丁不能替换导入。
您的解决方案是引用相同的符号。所以在 test_integrations.py
:
@patch("myapp.views.get_employee_sb7_data")