UNITSEST模拟找不到属性

发布于 2025-02-08 20:09:54 字数 2036 浏览 2 评论 0 原文

我会收到以下错误:

attributeError:< class'workflow.workflow.task'>没有属性“提取”

这是安排代码的方式,

src
|_ workflow
    |_ workflow.py
|_ tests
    |_ test_extract.py
|_ data_extractor:
    |_ data_extractor.py

这是 workflow.py

from data_extractor.data_extractor import DataExtractor

class Task:
    def __init__(self) -> None:
        self.extractor = DataExtractor()

    def extract_data(self):
        obj = self.extractor.extract()

in test_extract.py.py

from unittest import mock, TestCase
from workflow.workflow import Task


class TestSomeExtract(TestCase):

    @mock.patch("workflow.workflow.Task.extract")
    def test_extract_from_snowflake(self, mock_extract):

        actual_result = Task.extract_data()
        self.assertTrue(actual_result)


if __name__ == "__main__":
    TestCase.main()

我认为我做对了,但是...

更新24/6:

test_extract.py 中:

import unittest
from unittest import mock
from workflow.workflow import DataExtractor


@mock.patch("workflow.workflow.DataExtractor")
class TestSomeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):

        mock_extract.return_value.extract.return_value = True

        actual_result = DataExtractor().extract(name="entities", key="11") # return a list
        self.assertTrue(actual_result)
        mock_extract.assert_called_once_with(actual_result)

if __name__ == "__main__":
    unittest.main()

workflow.py 中:

from data_extractor.data_extractor import DataExtractor

class Task:

    def __init__(self, type: str, name: str) -> None:
        self.name = name
        self.type = type
        self.extractor = DataExtractor()

    def extract_data(self):

        obj = self.extractor.extract(name=self.name, key=key)

除了我在测试案例中添加了 ASSERT_CALLED_ONCE_ONCE_WITH

I'm getting the following error:

AttributeError: <class 'workflow.workflow.Task'> does not have the attribute 'extract'

This is how the codes are arranged

src
|_ workflow
    |_ workflow.py
|_ tests
    |_ test_extract.py
|_ data_extractor:
    |_ data_extractor.py

This is workflow.py:

from data_extractor.data_extractor import DataExtractor

class Task:
    def __init__(self) -> None:
        self.extractor = DataExtractor()

    def extract_data(self):
        obj = self.extractor.extract()

In test_extract.py:

from unittest import mock, TestCase
from workflow.workflow import Task


class TestSomeExtract(TestCase):

    @mock.patch("workflow.workflow.Task.extract")
    def test_extract_from_snowflake(self, mock_extract):

        actual_result = Task.extract_data()
        self.assertTrue(actual_result)


if __name__ == "__main__":
    TestCase.main()

I think I did it right but...

UPDATE 24/6:

In test_extract.py:

import unittest
from unittest import mock
from workflow.workflow import DataExtractor


@mock.patch("workflow.workflow.DataExtractor")
class TestSomeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):

        mock_extract.return_value.extract.return_value = True

        actual_result = DataExtractor().extract(name="entities", key="11") # return a list
        self.assertTrue(actual_result)
        mock_extract.assert_called_once_with(actual_result)

if __name__ == "__main__":
    unittest.main()

In workflow.py:

from data_extractor.data_extractor import DataExtractor

class Task:

    def __init__(self, type: str, name: str) -> None:
        self.name = name
        self.type = type
        self.extractor = DataExtractor()

    def extract_data(self):

        obj = self.extractor.extract(name=self.name, key=key)

Not much of difference besides I added assert_called_once_with in the test case.

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

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

发布评论

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

评论(1

漫漫岁月 2025-02-15 20:09:54

这是一个工作代码示例,基于您的更新版本:

import unittest
from unittest import mock


@mock.patch("workflow.workflow.DataExtractor")
class TestSnowFlakeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):
        from workflow.workflow import DataExtractor

        mock_extract.return_value.extract.return_value = True

        actual_result = DataExtractor().extract(name="stuff", key="11")
        self.assertTrue(actual_result)

一些要突出显示的内容:

  1. 当我们嘲笑某些内容时,我们替换属性。因此@mock.patch(“ workflow.workflow.dataextractor”)替换 dataextractor 属性属性 workflow.workflow.workflow 用模拟对象 - IT不会影响 data_extractor.data_extractor 软件包,因此我们不应直接使用 data_extractor.data_extractor package data_extractor.data_extractor。
  2. 强调上几点:@mock.patch(“ workflow.workflow.dataextractor”)被翻译成这两个语句:
    1. 导入workflow.workflow as Module_to_be_patched
    2. module_to_be_patched.dataextractor = magicMock()
  3. 模拟/补丁在我们测试开始时发生,因此,如果以下导入语句是全局:<代码>从workflow.workflow导入dataExtractor ,我们不会使用模拟版本,因为我们的测试模块中的名字 dataextractor 是原始 data_extractor.data_extractor 对象,然后执行补丁语句,这仅影响 WorkFlow 模块。
  4. 您需要在模拟返回语法上精确:您正在调用 dataextractor(),它等效于 mock_extract.return_value ,然后链接 excract(name) =“ supper”,key =“ 11”)等效于 .extract.return_value 。因此,完整的语法应为 mock_extract.return_value.extract.extract.return_value = true
  5. 在实际测试中,我们不会导入 dataextractor workflow.workflow.workflow ,而是导入 workflow.workflow 并调用其功能,依赖于 dataExtractor 被我们的测试替换的事实。

更新24/6:

这是一个更新的测试:

import unittest
from unittest import mock
from workflow.workflow import Task


@mock.patch("workflow.workflow.DataExtractor")
class TestSomeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):

        mock_extract.return_value.extract.return_value = True

        actual_result = Task(name="entities", key="11").extract_data()
        self.assertTrue(actual_result)
        mock_extract.assert_called_once_with()    # mock_extract is equal to DataExtractor(), which is called without parameters

需要注意的几件事:

  1. 我们测试 WorkFlow 模块,因此我们调用 task> Task> Task 的初始化,然后调用 extract_data
  2. 我们仅测试 WorkFlow 模块,因此我们模拟了其他依赖项,例如该模块的 dataExtractor
  3. 我必须对任务类进行较小的更改。例如,将其更改为从外部获取参数。

Here is a working code example, based in your updated version:

import unittest
from unittest import mock


@mock.patch("workflow.workflow.DataExtractor")
class TestSnowFlakeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):
        from workflow.workflow import DataExtractor

        mock_extract.return_value.extract.return_value = True

        actual_result = DataExtractor().extract(name="stuff", key="11")
        self.assertTrue(actual_result)

Some things to highlight:

  1. When we mock something, we replace the attribute. So @mock.patch("workflow.workflow.DataExtractor") replaces the DataExtractor attribute inside workflow.workflow package with a mock object - it doesn't affect the data_extractor.data_extractor package, so we shouldn't use the data_extractor.data_extractor package directly.
  2. Emphasising the previous point: @mock.patch("workflow.workflow.DataExtractor") is translated into these two statements:
    1. import workflow.workflow as module_to_be_patched
    2. module_to_be_patched.DataExtractor = MagicMock()
  3. The mock/patch happens at the beginning of our test, so if the following import statement had been global: from workflow.workflow import DataExtractor, we wouldn't use the mocked version, since we first name DataExtractor inside our test module to be the original data_extractor.data_extractor object and only then execute the patch statement, which only affects the workflow module.
  4. You need to be exact on the mock return syntax: you are calling DataExtractor() which is equivalent to mock_extract.return_value and then you chain the .extract(name="stuff", key="11") which is equivalent to .extract.return_value. Hence the full syntax should be mock_extract.return_value.extract.return_value = True
  5. In actual testing we wouldn't be importing DataExtractor from workflow.workflow, but rather import workflow.workflow and call its functionality, relying on the fact that DataExtractor was replaced by our test.

UPDATE 24/6:

Here is an updated test:

import unittest
from unittest import mock
from workflow.workflow import Task


@mock.patch("workflow.workflow.DataExtractor")
class TestSomeExtract(unittest.TestCase):
    def test_extract_from_snowflake(self, mock_extract):

        mock_extract.return_value.extract.return_value = True

        actual_result = Task(name="entities", key="11").extract_data()
        self.assertTrue(actual_result)
        mock_extract.assert_called_once_with()    # mock_extract is equal to DataExtractor(), which is called without parameters

A couple of things to notice:

  1. We Test the workflow module, hence we call the initialization of Task and then call extract_data.
  2. We only test workflow module, so we mock other dependencies like the DataExtractor of that module.
  3. I had to do minor changes to Task class. For example, change it to get the key parameter from outside.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文