【问题标题】:Understanding Mocking and SideEffects了解模拟和副作用
【发布时间】:2014-03-10 14:11:53
【问题描述】:

我是 Python 的新手,我了解测试,但是,我无法全神贯注地使用 Mocked Objects 和 side_effects。

这是我的方法:

@retry(every=RETRY_EVERY, until=RETRY_UNTIL)
@unique()
@sessionized(0)
def record_click(session, queue, mailing_id, member_id, link_id, timestamp, user_agent):
    message = session.query(Message).get((mailing_id, member_id))
    mailing = session.query(Mailing).get(mailing_id)
    # More code here

这是我的测试:

@mock.patch("audience.jobs.EventProvider")
@mock.patch("audience.jobs.enqueue_webhook")
@mock.patch("logging.exception")
@mock.patch("audience.jobs.audience_queues")
@mock.patch("audience.jobs.Session")
@mock.patch("audience.jobs.DatabaseConnector")
def test_track_click_publishes_event_to_sns(self, DatabaseConnector, Session, audience_queues, logger, enqueue_webhook, EventProvider):
    message_mock = mock.Mock(account_id=77)
    message_mock.record_open.return_value = True
    mailing_mock = mock.Mock(mailing_id=123)
    mailing_mock.recipient_groups.return_value = [111]
    session_query = Session.return_value.query.return_value
    session_query.side_effect = lambda arg: message_mock if isinstance(arg, tuple) else mailing_mock

    result = jobs.record_click(
        888,
        9999,
        2048,
        datetime.datetime(1999, 12, 31, 23, 59, 59, 999999).isoformat(),
        "Mozilla/5.0")

    self.assertIsNone(result)
    self.assertListEqual(EventProvider.mock_calls, [
        mock.call(),
        mock.call().publish_link_clicked(
            headers={'User-Agent': 'Mozilla/5.0'},
            mailing_id=888,
            account_id=77,
            contact_id=9999,
            link_id=2048,
            group_ids=[111]
        )
    ])
    self.assertListEqual(logger.mock_calls, [])

我一直收到的错误是:

而不是
call().publish_link_clicked(group_ids=[111], account_id=77, **etc)

这就是 UnitTest 中所称的
call().publish_link_clicked(group_ids=<MagicMock name='Session().query().get().recipient_groups' id='4557662736'>, account_id=<MagicMock name='Session().query().get().account_id' id='4557652048'>, **etc)

我做错了什么?

【问题讨论】:

  • sessionized() 也用于决定连接哪个数据库
  • 但大概session 参数来自sessionized 装饰器。它使用什么名称?您很可能没有在此处修补正确的位置。

标签: python unit-testing mocking side-effects


【解决方案1】:

不要打电话给Session()query();改用Mock.return_value attribute 来遍历调用图:

Session.return_value.query.return_value.side_effect = lambda arg: message_mock if isinstance(arg, tuple) else mailing_mock

我通常使用中间名来保存返回值:

session_query = Session.return_value.query.return_value
session_query.side_effect = lambda arg: message_mock if isinstance(arg, tuple) else mailing_mock

你还需要修补正确的Session类;这完全取决于您的代码如何生成record_clicksession 参数。有关详细信息,请参阅Where to Patch。如果@sessionized 装饰器产生了这个参数,并且它存在于audience.jobs 模块中,那么你没有修补正确的位置。

【讨论】:

  • @dennismonsewicz:您没有显示错误;你显示电话;从这些电话中,不清楚你到底觉得他们有什么问题。装饰器中的Session() mock 是如何产生的?你能用那个模块中使用的导入来展示那个代码吗?
猜你喜欢
  • 1970-01-01
  • 2011-10-17
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 2017-02-06
相关资源
最近更新 更多