Django 为什么模拟补丁只在运行特定测试而不是整个测试套件时才起作用?
我专门使用Django和Pytest来运行测试套件,并尝试测试当用户访问站点时,特定表单是否显示预期数据(集成测试) 这个特定的视图使用了一个存储过程,我正在模拟它,因为测试永远无法访问它 我的测试代码如下所示:Django 为什么模拟补丁只在运行特定测试而不是整个测试套件时才起作用?,django,unit-testing,mocking,pytest,liveservertestcase,Django,Unit Testing,Mocking,Pytest,Liveservertestcase,我专门使用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 no
#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))
如果我使用以下命令运行此测试本身:
pytest my_app/tests/test_integrations.py::SeniorPageTestCase
测试顺利通过。浏览器出现了——表单显示了我们预期的虚拟数据,一切正常
但是,如果我运行:
pytest我的应用程序
所有其他测试都会运行并通过-但是这个类中的所有测试都会失败,因为它没有修补函数
它尝试调用实际的存储过程(失败是因为它还不在生产服务器上),但失败了
为什么当我专门调用测试用例时,它会正确地进行修补?而当我只是在应用程序或项目级别上运行pytest
时,它不会正确地进行修补
我不知所措,不知道如何很好地调试它。非常感谢您提供的任何帮助,因此现在需要做的是在修补之前导入您的视图 让我们首先看看工作案例:
test_integrations.py
中:
@patch(“myapp.views.get_employee_sb7_data”)
你确定这就是原因吗@pytest.mark.usefixtures(“标准浏览器”)
是一个类属性。因此,它被所有测试重用。这会导致同样的症状吗?同样的情况也适用于setUp(),没有执行任何必要清理的tearDown()。测试在单独运行时工作,而不是在应用程序或项目级别运行时。该装置只打开一个浏览器,不做任何其他事情——测试完成后关闭——所以我认为这不会有任何影响。它在自己测试时工作。此外,setUp()还设置了数据——Django会在测试之间自动截断数据——这样就没有什么需要清理的了。日志中的错误明确显示它没有运行该设备,而是尝试运行存储过程-因此在运行整个套件时没有应用修补程序。在运行整个套件时,是否从其他位置导入此方法?我不知道,除非pytest在运行全套测试时与特定的测试类(我不相信它会这样做)有所不同;我在问题中添加了实用函数和调用该函数的视图,以便更容易理解正在发生的事情。它确实向我显示了两个不同的符号:get_employee_sb7_data
和my_app.utils.get_employee_sb7_data
。他们来自同一个地方,但名字不同。因此不同之处在于,views.py
在test\u integrations.py
之前被导入,并且在某种程度上仍然在范围内,但是当单独运行时,它首先导入测试用例(它确实如此)。测试该理论的方法是在测试用例中添加views.py作为import,然后两者都应该表现出相同的(不工作)行为。我按照您的建议在文件顶部添加了import(test_integrations.py),然后将该测试类函数的decorator更改为@patch(“get_employee_sb7_data”)
但收到错误:类型错误:需要一个有效的目标进行修补。您提供了:“获取员工数据”
My bad。更新。符号是作为绝对意义存在的,但作为“名称”,而不是目标。感谢您对需要发生的事情进行了出色的解释和更正。我现在对正在发生的事情有了更深入的了解(尽管mock仍然让我有点困惑——文档看起来像泥一样清晰!哈!)。我很感激!
# 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,
},
)