{
  "$type": "site.standard.document",
  "canonicalUrl": "https://rednafi.com/python/patch-where-the-object-is-used/",
  "description": "Master Python mocking: patch objects at their import location, not where they're defined, to avoid common unittest.mock pitfalls.",
  "path": "/python/patch-where-the-object-is-used/",
  "publishedAt": "2022-07-18T00:00:00.000Z",
  "site": "at://did:plc:fgtm2c26vfcj74rfmeggbyqj/site.standard.publication/3mnl6f7ob462z",
  "tags": [
    "Python",
    "Testing",
    "Pytest"
  ],
  "textContent": "I was reading Ned Bachelder's blog [Why your mock doesn't work] and it triggered an epiphany\nin me about a testing pattern that I've been using for a while without being aware that\nthere might be an aphorism on the practice.\n\n> Patch where the object is used; not where it's defined.\n\nTo understand it, consider the example below. Here, you have a module containing a function\nthat fetches data from some fictitious database.\n\nLet's say another module named service.py imports the get_data function and calls that\ninside of a function named process_data:\n\nNow, let's say we want to write a test for the service.process_data function. Since the\nfunction depends on db.get_data, we'll patch the get_data function and replace it with a\nmock object that returns a canned response. This will make sure that calling process\ndoesn't invoke the real get_data which might have side effects that we don't want to\ntrigger during test runs. Also, in this case, instead of returning a list of pseudo-random\nintegers, the replaced get_data function will deterministically return a list of known\nintegers.\n\nYou could patch get_data in multiple ways. Here's the first attempt:\n\nSince get_data is defined in the db.py module, we pass db.get_data to the patch\ndecorator. Unfortunately, if you run the above test with [pytest], you'll see that the test\nfails with the following error:\n\nThe original implementation of get_data returns a list of 4 pseudo-random integers where\nthe values lie between 100 and 200 whereas our patched version of get_data always returns\n[1, 2, 3, 4]. So, the test is failing because the get_data function didn't get patched\nproperly and it's calling the original get_data function during the test run.\n\nWhile the function get_data is defined in the db.py module, it's actally used in the\nservice.py module. So, we can avoid this missing target issue by patching get_data in\nthe location where it's used; not where it's defined. Here's how to do it:\n\nThis time, when you run the tests, pytest doesn't complain.\n\n\n\n\n[why your mock doesn't work]:\n    https://nedbatchelder.com/blog/201908/why_your_mock_doesnt_work.html\n\n[pytest]:\n    https://docs.pytest.org/en/latest/",
  "title": "Patch where the object is used"
}