【问题标题】:Mocking default values of attr.ib()模拟 attr.ib() 的默认值
【发布时间】:2018-10-29 18:00:44
【问题描述】:

我有类似下面的情况

@attrs(auto_attribs=True)
class ExampleClass:
  _prop: OtherClass = attrib(init=False, default=OtherClass())
  def some_func(self):
    test_var = OtherClass()
    test_var.some_func()
    self._prop.some_func()

class OtherClass:
  def some_func(self):
    raise NotImplementedException

def test_example(mocker):
  mocker.patch("path.to.example_class.OtherClass")
  sut = ExampleClass()
  sut.some_func()

所有的类和测试都在不同的文件中,并且 mocker 是 pytest_mock 提供的一个夹具,它只是 unittest.mock 的一个包装器,可以更轻松地进行清理。

我遇到的问题是,在运行单元测试时,test_var 被正确分配为补丁函数中的 MagicMock。所以当 test_var.some_func() 返回时,一切都很好。

self._prop.some_func() 被调用时,NotImplementedException 被提升,因为补丁似乎没有对此产生影响。

在我的单元测试中,我可以设置sut._prop = MagicMock(),但这是一个内部实现细节,使其成为一个脆弱的测试。

如何模拟属性中的默认变量以避免这种情况?

【问题讨论】:

  • 因为default=OtherClass() 将在模块导入时执行,而mocker.patch('modname.Class') 将在修补之前导入模块,所以当mocker 完成其工作时,默认的OtherClass 实例将已经初始化。这很难避免。如果OtherClassspam.py 中,ExampleClasseggs.py 中,那么排序mocker.patch('spam.OtherClass'); import eggs; eggs.ExampleClass().some_func() 应该可以工作,但是如果两个类都在同一个模块中,我看不到除了猴子修补default 之外的方法ExampleClass.__attrs_attrs__中的实例。
  • 谢谢,你触发我做更多的挖掘工作,并意识到我使用库错误,因为我将默认设置为实例,我每次都想要一个新实例,但这种情况不会发生.使用 lambda 我能够得到我的结果并且测试工作正常

标签: python pytest python-unittest python-attrs


【解决方案1】:

当我每次都想要一个新实例时,我在将默认值设置为实例时,我在功能上不正确地使用了该库。将 ExampleClass 更改为以下解决了我的问题

@attrs(auto_attribs=True)
class ExampleClass:
  _prop: OtherClass = attrib(init=False, factory=lambda: OtherClass())
  def some_func(self):
    test_var = OtherClass()
    test_var.some_func()
    self._prop.some_func()

【讨论】:

  • factory=lambda: OtherClass() 是不必要的复杂;只要不带任何参数,就去factory=OtherClass
  • 我的一个班级就是这样做的。但是,当您执行 factory=OtherClass 时,补丁也不起作用。我相信这是由于创建了一个工厂实例,然后在每次调用 lambda 时无法应用补丁。
猜你喜欢
  • 2018-04-19
  • 2015-09-09
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
  • 1970-01-01
  • 2019-06-13
  • 2012-12-26
相关资源
最近更新 更多