无法使用pytest莫克模拟方法

发布于 2025-02-08 06:12:19 字数 1889 浏览 0 评论 0原文

我有一个“ myllass”类,具有以下代码。

class MyClass:

    def __init__(update_type_id='1')
        
        self.update_type_id = update_type_id
        self._cursor = <database_connection).cursor()

    def update_start_dt(self):
        self._update_job_ctrl_start_dt()
        
    def _update_job_ctrl_start_dt(self):
        update_sql, v_1  = self._get_update_sql(self._update_type_id)
        logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
                
    def _get_update_sql(self, update_type_id: int) -> Tuple:
        sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
        self._run_sql(sql)
        record = self._cursor.fetchone()
        if record:
            return record
        else:
            logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
            raise Exception


    def _run_sql(self, sql_statement: str):
        try:
            self._cursor.execute(sql_statement)
        except (Exception, Error) as e:
            logger.error(f'Error {e} encountered when reading from table')
            raise e

我正在尝试使用PYTEST-MOCK编写一个测试功能,该测试功能将测试update_start_dt方法。该方法内部调用了一系列私人方法,我很难模拟通过所有私人方法运行的代码。谁能帮助我了解我们可以嘲笑什么?

我试图引用多个在线网站,但无法完整的图片。

class TestMyClass:
    
    def test_update_start_dt(mocker,mock_get_connection,mock_run_sql):
    
        mock_manager = mocker.Mock()
        mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
        mock_get_update_sql.return_value = ('123','234')
        myclass = MyClass(update_type_id='1')
        
        myclass.update_start_dt()

我在下面的测试代码下方遇到错误

update_sql, v_1  = self._get_update_sql(self._update_type_id)
ValueError: not enough values to unpack (expected 2, got 0)

I have a class 'MyClass' with code as below.

class MyClass:

    def __init__(update_type_id='1')
        
        self.update_type_id = update_type_id
        self._cursor = <database_connection).cursor()

    def update_start_dt(self):
        self._update_job_ctrl_start_dt()
        
    def _update_job_ctrl_start_dt(self):
        update_sql, v_1  = self._get_update_sql(self._update_type_id)
        logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
                
    def _get_update_sql(self, update_type_id: int) -> Tuple:
        sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
        self._run_sql(sql)
        record = self._cursor.fetchone()
        if record:
            return record
        else:
            logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
            raise Exception


    def _run_sql(self, sql_statement: str):
        try:
            self._cursor.execute(sql_statement)
        except (Exception, Error) as e:
            logger.error(f'Error {e} encountered when reading from table')
            raise e

I am trying to write a test function using pytest-mock which will test the update_start_dt method. The method internally invokes a series of private methods and I am having difficulty in mocking the code which runs through all the private methods. Can anyone help me to understand in what all ways we can mock?

I tried to refer multiple online websites but couldn't get a complete picture.

class TestMyClass:
    
    def test_update_start_dt(mocker,mock_get_connection,mock_run_sql):
    
        mock_manager = mocker.Mock()
        mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
        mock_get_update_sql.return_value = ('123','234')
        myclass = MyClass(update_type_id='1')
        
        myclass.update_start_dt()

I am getting error as below for above test code

update_sql, v_1  = self._get_update_sql(self._update_type_id)
ValueError: not enough values to unpack (expected 2, got 0)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久隐师 2025-02-15 06:12:19

这里的问题是,您正在使用要创建的模拟对象进行修补,为了进行测试,您无需明确创建模拟对象。下面显示的是您将如何对其进行测试,我们直接在类上patch

class MyClass:

    def __init__(self, update_type_id='1'):
        
        self._update_type_id = update_type_id
        self._cursor = None

    def update_start_dt(self):
        self._update_job_ctrl_start_dt()
        
    def _update_job_ctrl_start_dt(self):
        update_sql, v_1  = self._get_update_sql(self._update_type_id)
        logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
                
    def _get_update_sql(self, update_type_id: int):
        sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
        self._run_sql(sql)
        record = self._cursor.fetchone()
        if record:
            return record
        else:
            logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
            raise Exception


    def _run_sql(self, sql_statement: str):
        try:
            self._cursor.execute(sql_statement)
        except (Exception, Error) as e:
            logger.error(f'Error {e} encountered when reading from table')
            raise e



def test_update_start_dt(mocker):
    mock_get_update_sql = mocker.patch.object(MyClass, "_get_update_sql")
    mock_get_update_sql.return_value = ("123", "234")
    myclass = MyClass(update_type_id='1')

    myclass.update_start_dt()

=========================================== test session starts ============================================
platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
rootdir: ***
plugins: mock-3.7.0
collected 1 item                                                                                           

test_script.py .                                                                                     [100%]

======================================= 1 passed, 1 warning in 0.01s =======================================

如果您调用模拟对象而不是类,则您的代码将起作用。如下所示。

def test_update_start_dt(mocker):
    mock_manager = mocker.Mock()
    mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
    mock_get_update_sql.return_value = ('123','234')
    # Notice how we use `mock_manager` instead of MyClass
    # tests will now pass
    myclass = mock_manager(update_type_id='1')
    
    myclass.update_start_dt()

希望您看到现在的问题。

The issue here is that you are patching on a Mock object that you are creating, for the purposes of your test you do not need to explicitly create a Mock object. Shown below is how you would test it instead, where we patch directly on the class.

class MyClass:

    def __init__(self, update_type_id='1'):
        
        self._update_type_id = update_type_id
        self._cursor = None

    def update_start_dt(self):
        self._update_job_ctrl_start_dt()
        
    def _update_job_ctrl_start_dt(self):
        update_sql, v_1  = self._get_update_sql(self._update_type_id)
        logger.debug(f'Update sql: {update_sql} and v_1: {v_1}')
                
    def _get_update_sql(self, update_type_id: int):
        sql = f"SELECT start_sql, end_sql FROM <database.table> where update_type_key = {self._update_type_id}"
        self._run_sql(sql)
        record = self._cursor.fetchone()
        if record:
            return record
        else:
            logger.error(f'Record Not Found. Update type key ({update_type_id}) not found in the table in the database')
            raise Exception


    def _run_sql(self, sql_statement: str):
        try:
            self._cursor.execute(sql_statement)
        except (Exception, Error) as e:
            logger.error(f'Error {e} encountered when reading from table')
            raise e



def test_update_start_dt(mocker):
    mock_get_update_sql = mocker.patch.object(MyClass, "_get_update_sql")
    mock_get_update_sql.return_value = ("123", "234")
    myclass = MyClass(update_type_id='1')

    myclass.update_start_dt()

=========================================== test session starts ============================================
platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
rootdir: ***
plugins: mock-3.7.0
collected 1 item                                                                                           

test_script.py .                                                                                     [100%]

======================================= 1 passed, 1 warning in 0.01s =======================================

Your code would work if you called the Mock object you created instead of the class. That is shown below.

def test_update_start_dt(mocker):
    mock_manager = mocker.Mock()
    mock_get_update_sql = mock_manager.patch('MyClass._get_update_sql')
    mock_get_update_sql.return_value = ('123','234')
    # Notice how we use `mock_manager` instead of MyClass
    # tests will now pass
    myclass = mock_manager(update_type_id='1')
    
    myclass.update_start_dt()

Hopefully you see what the issue is now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文