Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django 为什么模拟补丁只在运行特定测试而不是整个测试套件时才起作用?_Django_Unit Testing_Mocking_Pytest_Liveservertestcase - Fatal编程技术网

Django 为什么模拟补丁只在运行特定测试而不是整个测试套件时才起作用?

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

我专门使用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))
如果我使用以下命令运行此测试本身:

pytest my_app/tests/test_integrations.py::SeniorPageTestCase

测试顺利通过。浏览器出现了——表单显示了我们预期的虚拟数据,一切正常

但是,如果我运行:

pytest我的应用程序

所有其他测试都会运行并通过-但是这个类中的所有测试都会失败,因为它没有修补函数

它尝试调用实际的存储过程(失败是因为它还不在生产服务器上),但失败了

为什么当我专门调用测试用例时,它会正确地进行修补?而当我只是在应用程序或项目级别上运行
pytest
时,它不会正确地进行修补


我不知所措,不知道如何很好地调试它。非常感谢您提供的任何帮助

,因此现在需要做的是在修补之前导入您的视图

让我们首先看看工作案例:

  • pytest导入test_集成文件
  • 执行测试并运行补丁装饰器的内部函数
  • 还没有导入utils,因此补丁会导入并替换该函数
  • 执行测试主体,它将url传递给测试客户端
  • 测试客户端导入解析器,然后导入视图,视图导入UTIL
  • 由于UTIL已修补,因此一切正常
  • 如果先运行另一个测试用例,该测试用例也会导入相同的视图,那么该导入将获胜,而补丁无法替换导入

    您的解决方案是引用相同的符号。因此,在
    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,
            },
        )