【问题标题】:Luigi parameter default values and mocksLuigi 参数默认值和模拟
【发布时间】:2015-09-09 13:29:46
【问题描述】:

我正在尝试模拟为 luigi 参数提供默认值的东西。

一个愚蠢的例子展示了我想要完成的事情:

正在测试的任务:

import luigi
from bar import Bar

bar = Bar()

class Baz(luigi.Task):

    qux = luigi.Parameter(default=bar.bar())

    def baz(self):
        return self.qux;

    def foo(self):
        return bar.bar()

单元测试代码:

import unittest
from mock import Mock, patch
from sut.baz import Baz

class TestMocking(unittest.TestCase):

    def test_baz_bar(self):
        self.assertEquals("bar", Baz().baz())

    @patch('sut.baz.bar')
    def test_patched_baz(self, mock_bar):
        mock_bar.bar = Mock(return_value="foo")
        self.assertEquals("foo", (Baz().baz()))

    @patch('sut.baz.bar')
    def test_patched_foo(self, mock_bar):
        mock_bar.bar = Mock(return_value="foo")
        self.assertEquals("foo", (Baz().foo()))

luigi.Parameter 逻辑似乎比补丁更早发生。

在本例中,test_patched_foo 通过,test_patched_baz 失败。所以补丁确实发生了,但发生在来自luigi.Parameter(default=bar.bar()) 行的调用之后。

是否可以模拟和修补以这种方式调用的东西?

【问题讨论】:

  • 在实际代码中,我通过延迟加载解决了这个问题。在我的玩具示例中复制解决方案时遇到问题,因此我不会将其作为自我答案发布。但我也不是特别喜欢这种解决方法。

标签: python unit-testing mocking luigi


【解决方案1】:

尝试将qux = luigi.Parameter(default=bar.bar()) 行移动到Baz 类的__init__ 方法中。将它放在__init__ 之外,它是在类定义时设置的,而不是实例创建,但是将它放入__init__ 将延迟它的创建到Baz 实例创建的位置。不要忘记在super 类上调用__init__:

class Baz(luigi.Task):

    def __init__(self, *args, **kwargs):
        super(Baz, self).__init__(*args, **kwargs)

        self.qux = luigi.Parameter(default=bar.bar())

    ...

【讨论】:

  • 一个有前途的想法,但与 luigi 参数的工作方式不兼容。 qux = luigi.Parameter(default=bar.bar()) 行创建了一个字段,稍后可以将其引用为 self.qux 但它不是 luigi.Parameter - 它是传递的值或默认规范的结果,在这种情况下是一个字符串。可能有一种方法可以绕过它并使用更标准的kwargs.pop 默认值,但我不确定 luigi 会喜欢它。不过可以试试看。
猜你喜欢
  • 2018-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多