【问题标题】:Mock Class with original spec Python具有原始规范 Python 的模拟类
【发布时间】:2018-05-02 15:23:21
【问题描述】:

我正在尝试使用 Mock package 在 Python 中模拟一个类,特别是在测试类中使用 patch decorator

from unittest import TestCase
from unittest.mock import Mock, patch

@patch("mypackage.subpackage.mymodule", autospec=True)
class MyClassTest(TestCase):
    def setUp(self):
        [...]

    def test_with_boundary_creates_job_flow_task(self):
        returned_value = self.some_class.return_something_from_my_module()

        self.assertIsInstance(returned_value, expected_value_class)

我希望我的模拟具有被模拟的类的原始行为,即除非我专门模拟一个属性/方法,否则它的行为应该与提供的类中的行为相同(具有其逻辑和返回价值)。

因此,当测试原始类中的非模拟方法但现有方法时,测试应该成功运行,而不是失败并出现以下(特定)错误:

AssertionError: <class 'unittest.mock.MagicMock'> is not an instance of <class 'airflow.contrib.operators.emr_create_job_flow_operator.EmrCreateJobFlowOperator'>

关于如何实现这一点的任何想法?

【问题讨论】:

  • 这是文档中描述的第一个场景:docs.python.org/3/library/unittest.mock.html#quick-guide
  • 看起来@patch("mypackage.subpackage.mymodule", autospec=True) 将模拟整个模块,而不仅仅是一个类。如果您希望您的类具有原始行为,除非您专门模拟一个属性或方法,那么为什么要模拟整个类而不仅仅是那些特定的属性或方法?
  • 顺便说一句,我不能高度推荐pytest 作为比内置单元测试更好的单元测试框架,它可以用作直接替代品(例如,它将运行现有的unittest 样式测试)。
  • @TomDalton 很抱歉我们的错误(我们是 python 的新手)。将 mymodule 更改为 myclass,我们只是想模拟一个类。我们想要这样做是因为我们有一些测试需要原始实例而不进行更改,而其他测试需要模拟函数,并且我们不希望有 2 个实例(some_class 和 some_class_with_mocks)。我们注意到您对 pytest 的建议。谢谢!

标签: python unit-testing mocking python-unittest


【解决方案1】:

这个错误的原因,是因为一个模块被模拟了,而不是类

AssertionError: <class 'unittest.mock.MagicMock'> is not an instance of 
<class ...EmrCreateJobFlowOperator'>

改变

@patch("mypackage.subpackage.mymodule"

@patch("mypackage.subpackage.mymodule.SomeClass"

我希望我的模拟具有被模拟的类的原始行为,

恐怕它是另一种方式,这将创建一个 App 的实例,其中所有方法和属性都被模拟,只有当你想模拟类特别是 __init__ 使用一种方法时才有用(或二)

mock_app = MagicMock(name='App', spec=App)
mock_app.method_one.return_value = whatever

我专门模拟了一个属性/方法method_one,而app 将拥有除method_one 之外的所有内容

mock_app = MagicMock(name='App', 'method_one', spec=App)
mock_app.method_one.return_value = 'mocked value'
app = App()

简而言之,您的补丁将是

  from airflow.contrib.operators.emr_create_job_flow_operator import EmrCreateJobFlowOperator
  @patch.object(EmrCreateJobFlowOperator, 'the_method')

【讨论】:

    【解决方案2】:

    我这样嘲笑它:

    from mypackage.subpackage.mymodule import MyClass
    
    class MyClassTest(TestCase):
        def setUp(self):
            [...]
    
        @patch.object(MyClass, 'method_to_mock', autospec=True)
        def test_with_boundary_creates_job_flow_task(self, mock_method):
            mock_method.return_value = expected_value_class() # Can use a stub
            returned_value = self.some_class.return_something_from_my_module()
    
            self.assertIsInstance(returned_value, expected_value_class)
    

    【讨论】:

      猜你喜欢
      • 2018-07-13
      • 1970-01-01
      • 1970-01-01
      • 2015-12-22
      • 1970-01-01
      • 2019-01-09
      • 2013-02-16
      • 1970-01-01
      • 2014-06-15
      相关资源
      最近更新 更多