[{"data":1,"prerenderedAt":1818},["ShallowReactive",2],{"page-\u002Fadvanced-mocking-test-doubles-in-python\u002Fautospec-strict-mocking\u002Fresolving-side_effect-and-return_value-conflicts\u002F":3},{"id":4,"title":5,"body":6,"description":1811,"extension":1812,"meta":1813,"navigation":195,"path":1814,"seo":1815,"stem":1816,"__hash__":1817},"content\u002Fadvanced-mocking-test-doubles-in-python\u002Fautospec-strict-mocking\u002Fresolving-side_effect-and-return_value-conflicts\u002Findex.md","Resolving side_effect and return_value conflicts",{"type":7,"value":8,"toc":1797},"minimark",[9,13,44,49,70,77,137,158,173,238,249,253,273,276,315,318,499,523,527,533,538,605,618,622,661,681,685,698,704,766,772,776,800,825,891,906,946,949,953,962,973,1070,1085,1135,1138,1188,1191,1241,1244,1248,1259,1334,1367,1373,1438,1441,1445,1457,1581,1587,1649,1655,1659,1690,1733,1762,1793],[10,11,5],"h1",{"id":12},"resolving-side_effect-and-return_value-conflicts",[14,15,16,17,21,22,25,26,29,30,33,34,37,38,40,41,43],"p",{},"Flaky test suites, silent ",[18,19,20],"code",{},"None"," returns, and unexpected ",[18,23,24],{},"StopIteration"," exceptions frequently trace back to a single root cause: misconfigured ",[18,27,28],{},"unittest.mock.Mock"," objects where ",[18,31,32],{},"side_effect"," and ",[18,35,36],{},"return_value"," compete for dispatch priority. In production-grade Python testing, understanding the exact attribute resolution order, state mutation traps, and framework-level scoping rules is non-negotiable. This guide provides a deterministic workflow for diagnosing, isolating, and permanently resolving ",[18,39,32],{}," vs ",[18,42,36],{}," conflicts across synchronous, asynchronous, and property-based testing paradigms.",[45,46,48],"h2",{"id":47},"the-mock-attribute-precedence-chain","The Mock Attribute Precedence Chain",[14,50,51,52,54,55,58,59,33,61,63,64,66,67,69],{},"The ",[18,53,28],{}," class implements a strict, deterministic evaluation order within its ",[18,56,57],{},"__call__"," method. When a mock is invoked, the interpreter does not merge or blend ",[18,60,32],{},[18,62,36],{},". Instead, it follows a hard precedence chain that completely bypasses ",[18,65,36],{}," if ",[18,68,32],{}," is truthy.",[14,71,72,73,76],{},"At the CPython implementation level, ",[18,74,75],{},"Mock.__call__"," executes the following sequence:",[78,79,80,92,107,119],"ol",{},[81,82,83,87,88,91],"li",{},[84,85,86],"strong",{},"Exception Check",": If ",[18,89,90],{},"self.side_effect"," is an exception class or instance, it is raised immediately.",[81,93,94,87,97,99,100,33,103,106],{},[84,95,96],{},"Callable Dispatch",[18,98,90],{}," is callable, it is invoked with the provided ",[18,101,102],{},"*args",[18,104,105],{},"**kwargs",". The return value of that callable becomes the mock's return value.",[81,108,109,87,112,114,115,118],{},[84,110,111],{},"Iterator Consumption",[18,113,90],{}," is an iterable, ",[18,116,117],{},"next()"," is called on it. The yielded value is returned.",[81,120,121,126,127,129,130,132,133,136],{},[84,122,123,124],{},"Fallback to ",[18,125,36],{},": Only if ",[18,128,90],{}," is explicitly ",[18,131,20],{}," or unset does the mock return ",[18,134,135],{},"self.return_value",".",[14,138,139,140,143,144,147,148,150,151,154,155,157],{},"This precedence is absolute. Assigning ",[18,141,142],{},"return_value = \"static\""," after setting ",[18,145,146],{},"m.side_effect = [1, 2]"," does not create a hybrid behavior. The iterable consumes the call, and once exhausted, the next invocation raises ",[18,149,24],{}," rather than falling back to ",[18,152,153],{},"\"static\"",". This design prevents ambiguous state resolution but frequently causes silent test failures when developers assume ",[18,156,36],{}," acts as a default fallback.",[14,159,160,161,166,167,169,170,172],{},"When architecting robust test doubles, understanding the foundational mechanics of ",[162,163,165],"a",{"href":164},"\u002Fadvanced-mocking-test-doubles-in-python\u002F","Advanced Mocking & Test Doubles in Python"," is critical to avoiding silent precedence violations in large codebases. The internal state of a mock is not a simple key-value store; it is a state machine tracking call history, iterator position, and attribute resolution paths. Reassigning ",[18,168,36],{}," post-initialization mutates the fallback state but leaves the iterator cursor or callable binding intact. Consequently, tests that pass in isolation may fail under parametrized or concurrent execution due to residual ",[18,171,32],{}," exhaustion.",[174,175,180],"pre",{"className":176,"code":177,"language":178,"meta":179,"style":179},"language-python shiki shiki-themes github-light github-dark","import unittest.mock\n\n# Conflict Reproduction: Iterable side_effect vs Static return_value\nm = unittest.mock.Mock(return_value='static')\nm.side_effect = [1, 2]\n\nprint(m()) # Output: 1\nprint(m()) # Output: 2\nprint(m()) # Raises StopIteration, return_value is completely bypassed\n","python","",[18,181,182,190,197,203,209,215,220,226,232],{"__ignoreMap":179},[183,184,187],"span",{"class":185,"line":186},"line",1,[183,188,189],{},"import unittest.mock\n",[183,191,193],{"class":185,"line":192},2,[183,194,196],{"emptyLinePlaceholder":195},true,"\n",[183,198,200],{"class":185,"line":199},3,[183,201,202],{},"# Conflict Reproduction: Iterable side_effect vs Static return_value\n",[183,204,206],{"class":185,"line":205},4,[183,207,208],{},"m = unittest.mock.Mock(return_value='static')\n",[183,210,212],{"class":185,"line":211},5,[183,213,214],{},"m.side_effect = [1, 2]\n",[183,216,218],{"class":185,"line":217},6,[183,219,196],{"emptyLinePlaceholder":195},[183,221,223],{"class":185,"line":222},7,[183,224,225],{},"print(m()) # Output: 1\n",[183,227,229],{"class":185,"line":228},8,[183,230,231],{},"print(m()) # Output: 2\n",[183,233,235],{"class":185,"line":234},9,[183,236,237],{},"print(m()) # Raises StopIteration, return_value is completely bypassed\n",[14,239,240,241,33,243,245,246,248],{},"To prevent this, treat ",[18,242,32],{},[18,244,36],{}," as mutually exclusive configuration axes. If dynamic behavior is required, encapsulate the fallback logic inside a single callable ",[18,247,32],{}," rather than relying on implicit precedence rules.",[45,250,252],{"id":251},"rapid-diagnosis-tracing-silent-overrides","Rapid Diagnosis: Tracing Silent Overrides",[14,254,255,256,258,259,261,262,264,265,268,269,272],{},"When a test suite exhibits intermittent failures or unexpected ",[18,257,20],{}," returns, the first step is to isolate the exact moment ",[18,260,32],{}," or ",[18,263,36],{}," is mutated. Standard print debugging is insufficient because ",[18,266,267],{},"conftest.py"," fixtures, autouse patches, or third-party plugins often reconfigure mocks during the ",[18,270,271],{},"pytest"," collection or setup phase.",[14,274,275],{},"A reliable diagnostic workflow involves three layers:",[78,277,278,293,305],{},[81,279,280,286,287,289,290,292],{},[84,281,282,285],{},[18,283,284],{},"mock_calls"," Inspection",": The ",[18,288,284],{}," attribute records every invocation, including positional and keyword arguments. Comparing the length of ",[18,291,284],{}," against expected call counts reveals silent exhaustion.",[81,294,295,301,302,304],{},[84,296,297,300],{},[18,298,299],{},"sys.settrace"," Hooking",": Registering a trace function allows you to intercept attribute access and assignment on the mock object before ",[18,303,57],{}," executes.",[81,306,307,310,311,314],{},[84,308,309],{},"State Dumping",": Serializing the mock's ",[18,312,313],{},"__dict__"," before and after invocation exposes hidden mutations.",[14,316,317],{},"The following diagnostic wrapper logs dispatch order and internal state transitions, making it trivial to identify framework-level interference:",[174,319,321],{"className":176,"code":320,"language":178,"meta":179,"style":179},"import unittest.mock\nimport sys\nimport inspect\n\nclass TracingMock(unittest.mock.Mock):\n def __call__(self, *args, **kwargs):\n # Capture pre-call state\n pre_state = {\n 'side_effect': self.side_effect,\n 'return_value': self.return_value,\n 'call_count': self.call_count,\n 'iterator_pos': getattr(self.side_effect, '__iter__', lambda: None)()\n }\n print(f'[TRACE] Pre-call state: {pre_state}')\n \n # Execute standard dispatch\n result = super().__call__(*args, **kwargs)\n \n # Capture post-call state\n post_state = {\n 'side_effect': self.side_effect,\n 'return_value': self.return_value,\n 'call_count': self.call_count\n }\n print(f'[TRACE] Post-call state: {post_state} -> Result: {result}')\n return result\n\n# Usage in a failing test\ndef test_diagnose_override():\n mock = TracingMock(return_value=\"fallback\")\n mock.side_effect = lambda x: x * 2\n assert mock(5) == 10 # Logs dispatch order, confirms callable precedence\n",[18,322,323,327,332,337,341,346,351,356,361,366,372,378,384,390,396,402,408,414,419,425,431,436,441,447,452,458,464,469,475,481,487,493],{"__ignoreMap":179},[183,324,325],{"class":185,"line":186},[183,326,189],{},[183,328,329],{"class":185,"line":192},[183,330,331],{},"import sys\n",[183,333,334],{"class":185,"line":199},[183,335,336],{},"import inspect\n",[183,338,339],{"class":185,"line":205},[183,340,196],{"emptyLinePlaceholder":195},[183,342,343],{"class":185,"line":211},[183,344,345],{},"class TracingMock(unittest.mock.Mock):\n",[183,347,348],{"class":185,"line":217},[183,349,350],{}," def __call__(self, *args, **kwargs):\n",[183,352,353],{"class":185,"line":222},[183,354,355],{}," # Capture pre-call state\n",[183,357,358],{"class":185,"line":228},[183,359,360],{}," pre_state = {\n",[183,362,363],{"class":185,"line":234},[183,364,365],{}," 'side_effect': self.side_effect,\n",[183,367,369],{"class":185,"line":368},10,[183,370,371],{}," 'return_value': self.return_value,\n",[183,373,375],{"class":185,"line":374},11,[183,376,377],{}," 'call_count': self.call_count,\n",[183,379,381],{"class":185,"line":380},12,[183,382,383],{}," 'iterator_pos': getattr(self.side_effect, '__iter__', lambda: None)()\n",[183,385,387],{"class":185,"line":386},13,[183,388,389],{}," }\n",[183,391,393],{"class":185,"line":392},14,[183,394,395],{}," print(f'[TRACE] Pre-call state: {pre_state}')\n",[183,397,399],{"class":185,"line":398},15,[183,400,401],{}," \n",[183,403,405],{"class":185,"line":404},16,[183,406,407],{}," # Execute standard dispatch\n",[183,409,411],{"class":185,"line":410},17,[183,412,413],{}," result = super().__call__(*args, **kwargs)\n",[183,415,417],{"class":185,"line":416},18,[183,418,401],{},[183,420,422],{"class":185,"line":421},19,[183,423,424],{}," # Capture post-call state\n",[183,426,428],{"class":185,"line":427},20,[183,429,430],{}," post_state = {\n",[183,432,434],{"class":185,"line":433},21,[183,435,365],{},[183,437,439],{"class":185,"line":438},22,[183,440,371],{},[183,442,444],{"class":185,"line":443},23,[183,445,446],{}," 'call_count': self.call_count\n",[183,448,450],{"class":185,"line":449},24,[183,451,389],{},[183,453,455],{"class":185,"line":454},25,[183,456,457],{}," print(f'[TRACE] Post-call state: {post_state} -> Result: {result}')\n",[183,459,461],{"class":185,"line":460},26,[183,462,463],{}," return result\n",[183,465,467],{"class":185,"line":466},27,[183,468,196],{"emptyLinePlaceholder":195},[183,470,472],{"class":185,"line":471},28,[183,473,474],{},"# Usage in a failing test\n",[183,476,478],{"class":185,"line":477},29,[183,479,480],{},"def test_diagnose_override():\n",[183,482,484],{"class":185,"line":483},30,[183,485,486],{}," mock = TracingMock(return_value=\"fallback\")\n",[183,488,490],{"class":185,"line":489},31,[183,491,492],{}," mock.side_effect = lambda x: x * 2\n",[183,494,496],{"class":185,"line":495},32,[183,497,498],{}," assert mock(5) == 10 # Logs dispatch order, confirms callable precedence\n",[14,500,501,502,504,505,508,509,511,512,515,516,518,519,522],{},"When integrating this into a ",[18,503,271],{}," suite, run tests with ",[18,506,507],{},"pytest -s"," to capture stdout traces. If the trace shows ",[18,510,32],{}," changing between test collection and execution, the culprit is typically a session-scoped fixture or a ",[18,513,514],{},"monkeypatch"," that mutates shared mock instances. Always verify that ",[18,517,267],{}," does not reassign mock attributes after the initial ",[18,520,521],{},"@pytest.fixture"," yield.",[45,524,526],{"id":525},"minimal-reproduction-patterns-for-flaky-tests","Minimal Reproduction Patterns for Flaky Tests",[14,528,529,530,532],{},"Flakiness in mock configuration rarely stems from the mock itself; it emerges from test runner concurrency, fixture scoping, or implicit state sharing. Below are three isolated ",[18,531,271],{}," patterns that reliably reproduce precedence conflicts, along with exact failure signatures and resolution strategies.",[534,535,537],"h3",{"id":536},"pattern-1-iterable-exhaustion-across-parametrized-tests","Pattern 1: Iterable Exhaustion Across Parametrized Tests",[174,539,541],{"className":176,"code":540,"language":178,"meta":179,"style":179},"import pytest\nimport unittest.mock\n\n@pytest.fixture\ndef shared_mock():\n m = unittest.mock.Mock()\n m.side_effect = [1, 2, 3]\n return m\n\n@pytest.mark.parametrize(\"expected\", [1, 2, 3])\ndef test_iterable_exhaustion(shared_mock, expected):\n # Fails on second and third runs due to shared iterator state\n assert shared_mock() == expected\n",[18,542,543,548,552,556,561,566,571,576,581,585,590,595,600],{"__ignoreMap":179},[183,544,545],{"class":185,"line":186},[183,546,547],{},"import pytest\n",[183,549,550],{"class":185,"line":192},[183,551,189],{},[183,553,554],{"class":185,"line":199},[183,555,196],{"emptyLinePlaceholder":195},[183,557,558],{"class":185,"line":205},[183,559,560],{},"@pytest.fixture\n",[183,562,563],{"class":185,"line":211},[183,564,565],{},"def shared_mock():\n",[183,567,568],{"class":185,"line":217},[183,569,570],{}," m = unittest.mock.Mock()\n",[183,572,573],{"class":185,"line":222},[183,574,575],{}," m.side_effect = [1, 2, 3]\n",[183,577,578],{"class":185,"line":228},[183,579,580],{}," return m\n",[183,582,583],{"class":185,"line":234},[183,584,196],{"emptyLinePlaceholder":195},[183,586,587],{"class":185,"line":368},[183,588,589],{},"@pytest.mark.parametrize(\"expected\", [1, 2, 3])\n",[183,591,592],{"class":185,"line":374},[183,593,594],{},"def test_iterable_exhaustion(shared_mock, expected):\n",[183,596,597],{"class":185,"line":380},[183,598,599],{}," # Fails on second and third runs due to shared iterator state\n",[183,601,602],{"class":185,"line":386},[183,603,604],{}," assert shared_mock() == expected\n",[14,606,607,610,611,613,614,617],{},[84,608,609],{},"Failure Trace",": ",[18,612,24],{}," on the second parametrized run. The iterator is not reset between ",[18,615,616],{},"pytest.mark.parametrize"," iterations.",[534,619,621],{"id":620},"pattern-2-callable-exception-vs-return-value-collision","Pattern 2: Callable Exception vs Return Value Collision",[174,623,625],{"className":176,"code":624,"language":178,"meta":179,"style":179},"def test_exception_override():\n m = unittest.mock.Mock(return_value=\"success\")\n m.side_effect = ValueError(\"intentional\")\n \n # This raises ValueError, bypassing return_value entirely\n with pytest.raises(ValueError):\n m()\n",[18,626,627,632,637,642,646,651,656],{"__ignoreMap":179},[183,628,629],{"class":185,"line":186},[183,630,631],{},"def test_exception_override():\n",[183,633,634],{"class":185,"line":192},[183,635,636],{}," m = unittest.mock.Mock(return_value=\"success\")\n",[183,638,639],{"class":185,"line":199},[183,640,641],{}," m.side_effect = ValueError(\"intentional\")\n",[183,643,644],{"class":185,"line":205},[183,645,401],{},[183,647,648],{"class":185,"line":211},[183,649,650],{}," # This raises ValueError, bypassing return_value entirely\n",[183,652,653],{"class":185,"line":217},[183,654,655],{}," with pytest.raises(ValueError):\n",[183,657,658],{"class":185,"line":222},[183,659,660],{}," m()\n",[14,662,663,666,667,670,671,674,675,677,678,680],{},[84,664,665],{},"Failure Signature",": Tests expecting ",[18,668,669],{},"\"success\""," will fail with ",[18,672,673],{},"ValueError",". The precedence chain evaluates ",[18,676,32],{}," first, raising the exception before ",[18,679,36],{}," is consulted.",[534,682,684],{"id":683},"pattern-3-concurrent-runner-state-pollution","Pattern 3: Concurrent Runner State Pollution",[14,686,687,688,691,692,694,695,697],{},"When using ",[18,689,690],{},"pytest-xdist",", session-scoped mocks are shared across worker processes. If one worker exhausts an iterable ",[18,693,32],{},", subsequent workers inherit the exhausted state, causing ",[18,696,36],{}," to appear \"broken.\"",[14,699,700,703],{},[84,701,702],{},"Resolution Fixture",":",[174,705,707],{"className":176,"code":706,"language":178,"meta":179,"style":179},"import pytest\nimport unittest.mock\n\n@pytest.fixture(autouse=True)\ndef reset_mock_state():\n # Auto-resets all Mock instances in the test module's namespace\n yield\n # Post-test cleanup ensures deterministic state for next run\n import gc\n for obj in gc.get_objects():\n if isinstance(obj, unittest.mock.Mock):\n obj.reset_mock()\n",[18,708,709,713,717,721,726,731,736,741,746,751,756,761],{"__ignoreMap":179},[183,710,711],{"class":185,"line":186},[183,712,547],{},[183,714,715],{"class":185,"line":192},[183,716,189],{},[183,718,719],{"class":185,"line":199},[183,720,196],{"emptyLinePlaceholder":195},[183,722,723],{"class":185,"line":205},[183,724,725],{},"@pytest.fixture(autouse=True)\n",[183,727,728],{"class":185,"line":211},[183,729,730],{},"def reset_mock_state():\n",[183,732,733],{"class":185,"line":217},[183,734,735],{}," # Auto-resets all Mock instances in the test module's namespace\n",[183,737,738],{"class":185,"line":222},[183,739,740],{}," yield\n",[183,742,743],{"class":185,"line":228},[183,744,745],{}," # Post-test cleanup ensures deterministic state for next run\n",[183,747,748],{"class":185,"line":234},[183,749,750],{}," import gc\n",[183,752,753],{"class":185,"line":368},[183,754,755],{}," for obj in gc.get_objects():\n",[183,757,758],{"class":185,"line":374},[183,759,760],{}," if isinstance(obj, unittest.mock.Mock):\n",[183,762,763],{"class":185,"line":380},[183,764,765],{}," obj.reset_mock()\n",[14,767,768,769,771],{},"This fixture guarantees that ",[18,770,32],{}," iterators and call counters are cleared between parametrized or concurrent executions, eliminating cross-test pollution.",[45,773,775],{"id":774},"async-generator-edge-cases","Async & Generator Edge Cases",[14,777,778,781,782,785,786,789,790,792,793,796,797,136],{},[18,779,780],{},"unittest.mock.AsyncMock"," inherits the same precedence rules as ",[18,783,784],{},"Mock",", but introduces additional complexity due to the ",[18,787,788],{},"await"," protocol and coroutine wrapping. When ",[18,791,32],{}," is assigned to an ",[18,794,795],{},"AsyncMock",", the framework expects either an awaitable, a coroutine function, or an iterable of awaitables. Passing a synchronous callable without proper wrapping triggers ",[18,798,799],{},"TypeError: object NoneType can't be used in 'await' expression",[14,801,802,803,805,806,808,809,811,812,815,816,818,819,821,822,824],{},"Generator exhaustion conflicts are particularly insidious in async contexts. If ",[18,804,32],{}," is a generator, ",[18,807,795],{}," will consume it via ",[18,810,117],{},". Once exhausted, subsequent ",[18,813,814],{},"await mock()"," calls raise ",[18,817,24],{}," instead of falling back to ",[18,820,36],{},". This behavior violates developer intuition because ",[18,823,36],{}," is often assumed to act as a default coroutine.",[174,826,828],{"className":176,"code":827,"language":178,"meta":179,"style":179},"import asyncio\nimport unittest.mock\n\nasync def conditional_side_effect(*args):\n if args[0] == 'critical':\n return await asyncio.sleep(0, result=\"critical_response\")\n return 'default'\n\nmock = unittest.mock.AsyncMock(side_effect=conditional_side_effect)\n\nasync def test_async_dispatch():\n assert await mock('critical') == 'critical_response'\n assert await mock('normal') == 'default'\n",[18,829,830,835,839,843,848,853,858,863,867,872,876,881,886],{"__ignoreMap":179},[183,831,832],{"class":185,"line":186},[183,833,834],{},"import asyncio\n",[183,836,837],{"class":185,"line":192},[183,838,189],{},[183,840,841],{"class":185,"line":199},[183,842,196],{"emptyLinePlaceholder":195},[183,844,845],{"class":185,"line":205},[183,846,847],{},"async def conditional_side_effect(*args):\n",[183,849,850],{"class":185,"line":211},[183,851,852],{}," if args[0] == 'critical':\n",[183,854,855],{"class":185,"line":217},[183,856,857],{}," return await asyncio.sleep(0, result=\"critical_response\")\n",[183,859,860],{"class":185,"line":222},[183,861,862],{}," return 'default'\n",[183,864,865],{"class":185,"line":228},[183,866,196],{"emptyLinePlaceholder":195},[183,868,869],{"class":185,"line":234},[183,870,871],{},"mock = unittest.mock.AsyncMock(side_effect=conditional_side_effect)\n",[183,873,874],{"class":185,"line":368},[183,875,196],{"emptyLinePlaceholder":195},[183,877,878],{"class":185,"line":374},[183,879,880],{},"async def test_async_dispatch():\n",[183,882,883],{"class":185,"line":380},[183,884,885],{}," assert await mock('critical') == 'critical_response'\n",[183,887,888],{"class":185,"line":386},[183,889,890],{}," assert await mock('normal') == 'default'\n",[14,892,893,894,898,899,902,903,905],{},"To prevent accidental attribute leakage that exacerbates precedence bugs in async contexts, enforce strict interface boundaries. Implementing ",[162,895,897],{"href":896},"\u002Fadvanced-mocking-test-doubles-in-python\u002Fautospec-strict-mocking\u002F","Autospec & Strict Mocking"," ensures that only explicitly defined methods are accessible, preventing silent fallbacks to ",[18,900,901],{},"MagicMock","'s default behavior. When working with generators, explicitly wrap them in a callable that catches ",[18,904,24],{}," and returns a precomputed awaitable:",[174,907,909],{"className":176,"code":908,"language":178,"meta":179,"style":179},"def safe_async_generator_wrapper(gen):\n def wrapper(*args, **kwargs):\n try:\n return next(gen)\n except StopIteration:\n return asyncio.coroutine(lambda: \"fallback\")()\n return wrapper\n",[18,910,911,916,921,926,931,936,941],{"__ignoreMap":179},[183,912,913],{"class":185,"line":186},[183,914,915],{},"def safe_async_generator_wrapper(gen):\n",[183,917,918],{"class":185,"line":192},[183,919,920],{}," def wrapper(*args, **kwargs):\n",[183,922,923],{"class":185,"line":199},[183,924,925],{}," try:\n",[183,927,928],{"class":185,"line":205},[183,929,930],{}," return next(gen)\n",[183,932,933],{"class":185,"line":211},[183,934,935],{}," except StopIteration:\n",[183,937,938],{"class":185,"line":217},[183,939,940],{}," return asyncio.coroutine(lambda: \"fallback\")()\n",[183,942,943],{"class":185,"line":222},[183,944,945],{}," return wrapper\n",[14,947,948],{},"This pattern guarantees deterministic behavior regardless of iterator state, eliminating race conditions in high-throughput async test suites.",[45,950,952],{"id":951},"profiling-mock-call-overhead","Profiling Mock Call Overhead",[14,954,955,956,958,959,961],{},"In large test suites, deeply nested ",[18,957,32],{}," chains or excessive ",[18,960,284],{}," inspection can introduce measurable dispatch latency. Profiling this overhead requires isolating the mock's internal attribute lookup from the actual callable execution.",[14,963,964,965,968,969,972],{},"Using ",[18,966,967],{},"pytest-benchmark"," combined with ",[18,970,971],{},"cProfile"," provides granular visibility into mock resolution paths. The following setup measures dispatch latency without altering test semantics:",[174,974,976],{"className":176,"code":975,"language":178,"meta":179,"style":179},"import pytest\nimport cProfile\nimport pstats\nimport io\nimport unittest.mock\n\n@pytest.fixture\ndef profiled_mock():\n m = unittest.mock.Mock()\n m.side_effect = lambda x: x ** 2\n return m\n\ndef test_profile_dispatch(benchmark, profiled_mock):\n def run_calls():\n for _ in range(10000):\n profiled_mock(5)\n \n # Benchmark isolates mock overhead from test framework setup\n result = benchmark(run_calls)\n assert profiled_mock.call_count == 10000\n",[18,977,978,982,987,992,997,1001,1005,1009,1014,1018,1023,1027,1031,1036,1041,1046,1051,1055,1060,1065],{"__ignoreMap":179},[183,979,980],{"class":185,"line":186},[183,981,547],{},[183,983,984],{"class":185,"line":192},[183,985,986],{},"import cProfile\n",[183,988,989],{"class":185,"line":199},[183,990,991],{},"import pstats\n",[183,993,994],{"class":185,"line":205},[183,995,996],{},"import io\n",[183,998,999],{"class":185,"line":211},[183,1000,189],{},[183,1002,1003],{"class":185,"line":217},[183,1004,196],{"emptyLinePlaceholder":195},[183,1006,1007],{"class":185,"line":222},[183,1008,560],{},[183,1010,1011],{"class":185,"line":228},[183,1012,1013],{},"def profiled_mock():\n",[183,1015,1016],{"class":185,"line":234},[183,1017,570],{},[183,1019,1020],{"class":185,"line":368},[183,1021,1022],{}," m.side_effect = lambda x: x ** 2\n",[183,1024,1025],{"class":185,"line":374},[183,1026,580],{},[183,1028,1029],{"class":185,"line":380},[183,1030,196],{"emptyLinePlaceholder":195},[183,1032,1033],{"class":185,"line":386},[183,1034,1035],{},"def test_profile_dispatch(benchmark, profiled_mock):\n",[183,1037,1038],{"class":185,"line":392},[183,1039,1040],{}," def run_calls():\n",[183,1042,1043],{"class":185,"line":398},[183,1044,1045],{}," for _ in range(10000):\n",[183,1047,1048],{"class":185,"line":404},[183,1049,1050],{}," profiled_mock(5)\n",[183,1052,1053],{"class":185,"line":410},[183,1054,401],{},[183,1056,1057],{"class":185,"line":416},[183,1058,1059],{}," # Benchmark isolates mock overhead from test framework setup\n",[183,1061,1062],{"class":185,"line":421},[183,1063,1064],{}," result = benchmark(run_calls)\n",[183,1066,1067],{"class":185,"line":427},[183,1068,1069],{}," assert profiled_mock.call_count == 10000\n",[14,1071,1072,1073,1076,1077,1080,1081,1084],{},"To profile at the module level, run ",[18,1074,1075],{},"pytest --profile"," (via ",[18,1078,1079],{},"pytest-profiling",") and filter the resulting ",[18,1082,1083],{},"profile.prof"," file:",[174,1086,1090],{"className":1087,"code":1088,"language":1089,"meta":179,"style":179},"language-bash shiki shiki-themes github-light github-dark","python -m cProfile -o mock_profile.prof -m pytest tests\u002F -k \"mock\"\npython -c \"import pstats; p = pstats.Stats('mock_profile.prof'); p.sort_stats('cumulative').print_stats('unittest.mock')\"\n","bash",[18,1091,1092,1125],{"__ignoreMap":179},[183,1093,1094,1097,1101,1105,1108,1111,1113,1116,1119,1122],{"class":185,"line":186},[183,1095,178],{"class":1096},"sScJk",[183,1098,1100],{"class":1099},"sj4cs"," -m",[183,1102,1104],{"class":1103},"sZZnC"," cProfile",[183,1106,1107],{"class":1099}," -o",[183,1109,1110],{"class":1103}," mock_profile.prof",[183,1112,1100],{"class":1099},[183,1114,1115],{"class":1103}," pytest",[183,1117,1118],{"class":1103}," tests\u002F",[183,1120,1121],{"class":1099}," -k",[183,1123,1124],{"class":1103}," \"mock\"\n",[183,1126,1127,1129,1132],{"class":185,"line":192},[183,1128,178],{"class":1096},[183,1130,1131],{"class":1099}," -c",[183,1133,1134],{"class":1103}," \"import pstats; p = pstats.Stats('mock_profile.prof'); p.sort_stats('cumulative').print_stats('unittest.mock')\"\n",[14,1136,1137],{},"High overhead typically stems from:",[78,1139,1140,1149,1161],{},[81,1141,1142,1148],{},[84,1143,1144,1145,1147],{},"Deeply nested ",[18,1146,32],{}," chains",": Each callable invocation adds stack depth. Flatten chains into a single dispatcher.",[81,1150,1151,1157,1158,1160],{},[84,1152,1153,1154,1156],{},"Excessive ",[18,1155,284],{}," inspection",": Accessing ",[18,1159,284],{}," triggers list traversal. Cache call counts locally if asserting frequently.",[81,1162,1163,610,1166,1168,1169,1172,1173,1176,1177,1180,1181,261,1184,1187],{},[84,1164,1165],{},"MagicMethod resolution",[18,1167,901],{}," dynamically generates ",[18,1170,1171],{},"__getitem__",", ",[18,1174,1175],{},"__iter__",", and ",[18,1178,1179],{},"__contains__",". Each access incurs descriptor protocol overhead. Use ",[18,1182,1183],{},"spec",[18,1185,1186],{},"autospec"," to disable unnecessary magic method generation.",[14,1189,1190],{},"A lightweight profiling wrapper can isolate attribute lookup latency:",[174,1192,1194],{"className":176,"code":1193,"language":178,"meta":179,"style":179},"import time\nimport unittest.mock\n\nclass LatencyTracingMock(unittest.mock.Mock):\n def __call__(self, *args, **kwargs):\n start = time.perf_counter_ns()\n result = super().__call__(*args, **kwargs)\n elapsed = time.perf_counter_ns() - start\n print(f\"[LATENCY] {elapsed}ns for dispatch\")\n return result\n",[18,1195,1196,1201,1205,1209,1214,1218,1223,1227,1232,1237],{"__ignoreMap":179},[183,1197,1198],{"class":185,"line":186},[183,1199,1200],{},"import time\n",[183,1202,1203],{"class":185,"line":192},[183,1204,189],{},[183,1206,1207],{"class":185,"line":199},[183,1208,196],{"emptyLinePlaceholder":195},[183,1210,1211],{"class":185,"line":205},[183,1212,1213],{},"class LatencyTracingMock(unittest.mock.Mock):\n",[183,1215,1216],{"class":185,"line":211},[183,1217,350],{},[183,1219,1220],{"class":185,"line":217},[183,1221,1222],{}," start = time.perf_counter_ns()\n",[183,1224,1225],{"class":185,"line":222},[183,1226,413],{},[183,1228,1229],{"class":185,"line":228},[183,1230,1231],{}," elapsed = time.perf_counter_ns() - start\n",[183,1233,1234],{"class":185,"line":234},[183,1235,1236],{}," print(f\"[LATENCY] {elapsed}ns for dispatch\")\n",[183,1238,1239],{"class":185,"line":368},[183,1240,463],{},[14,1242,1243],{},"This wrapper reveals whether latency originates from the mock's internal precedence resolution or from the underlying callable logic.",[45,1245,1247],{"id":1246},"strategic-resolution-fallback-patterns","Strategic Resolution & Fallback Patterns",[14,1249,1250,1251,40,1253,1255,1256,1258],{},"To permanently resolve ",[18,1252,32],{},[18,1254,36],{}," conflicts, implement explicit dispatch logic that enforces mutual exclusivity. A custom callable ",[18,1257,32],{}," can inspect arguments, track state, and conditionally delegate to a static fallback, eliminating reliance on implicit precedence rules.",[174,1260,1262],{"className":176,"code":1261,"language":178,"meta":179,"style":179},"import unittest.mock\n\ndef deterministic_dispatcher(static_fallback, dynamic_fn):\n def wrapper(*args, **kwargs):\n # Explicitly check conditions before delegating\n if kwargs.get('force_dynamic', False):\n return dynamic_fn(*args, **kwargs)\n return static_fallback\n return wrapper\n\nmock = unittest.mock.Mock()\nmock.side_effect = deterministic_dispatcher(\n static_fallback=\"default\",\n dynamic_fn=lambda x: x * 10\n)\n",[18,1263,1264,1268,1272,1277,1281,1286,1291,1296,1301,1305,1309,1314,1319,1324,1329],{"__ignoreMap":179},[183,1265,1266],{"class":185,"line":186},[183,1267,189],{},[183,1269,1270],{"class":185,"line":192},[183,1271,196],{"emptyLinePlaceholder":195},[183,1273,1274],{"class":185,"line":199},[183,1275,1276],{},"def deterministic_dispatcher(static_fallback, dynamic_fn):\n",[183,1278,1279],{"class":185,"line":205},[183,1280,920],{},[183,1282,1283],{"class":185,"line":211},[183,1284,1285],{}," # Explicitly check conditions before delegating\n",[183,1287,1288],{"class":185,"line":217},[183,1289,1290],{}," if kwargs.get('force_dynamic', False):\n",[183,1292,1293],{"class":185,"line":222},[183,1294,1295],{}," return dynamic_fn(*args, **kwargs)\n",[183,1297,1298],{"class":185,"line":228},[183,1299,1300],{}," return static_fallback\n",[183,1302,1303],{"class":185,"line":234},[183,1304,945],{},[183,1306,1307],{"class":185,"line":368},[183,1308,196],{"emptyLinePlaceholder":195},[183,1310,1311],{"class":185,"line":374},[183,1312,1313],{},"mock = unittest.mock.Mock()\n",[183,1315,1316],{"class":185,"line":380},[183,1317,1318],{},"mock.side_effect = deterministic_dispatcher(\n",[183,1320,1321],{"class":185,"line":386},[183,1322,1323],{}," static_fallback=\"default\",\n",[183,1325,1326],{"class":185,"line":392},[183,1327,1328],{}," dynamic_fn=lambda x: x * 10\n",[183,1330,1331],{"class":185,"line":398},[183,1332,1333],{},")\n",[14,1335,1336,1337,1340,1341,1344,1345,1348,1349,1172,1352,1176,1354,1357,1358,261,1360,1362,1363,1366],{},"When cleaning up mock state, prefer ",[18,1338,1339],{},"mock.configure_mock(side_effect=None, return_value=\"new_default\")"," over direct attribute assignment. ",[18,1342,1343],{},"configure_mock"," validates inputs and resets internal iterator cursors, whereas direct assignment leaves residual state. For comprehensive cleanup, ",[18,1346,1347],{},"mock.reset_mock()"," clears ",[18,1350,1351],{},"call_count",[18,1353,284],{},[18,1355,1356],{},"method_calls",", but does not reset ",[18,1359,32],{},[18,1361,36],{},". Always pair ",[18,1364,1365],{},"reset_mock()"," with explicit reconfiguration.",[14,1368,1369,1370,1372],{},"A reusable ",[18,1371,271],{}," helper enforces mutual exclusivity at fixture setup:",[174,1374,1376],{"className":176,"code":1375,"language":178,"meta":179,"style":179},"import pytest\nimport unittest.mock\n\n@pytest.fixture\ndef exclusive_mock():\n m = unittest.mock.Mock()\n yield m\n # Post-test validation\n if m.side_effect is not None and m.return_value is not None:\n raise AssertionError(\"Mutual exclusivity violated: both side_effect and return_value are set.\")\n m.reset_mock()\n m.side_effect = None\n m.return_value = None\n",[18,1377,1378,1382,1386,1390,1394,1399,1403,1408,1413,1418,1423,1428,1433],{"__ignoreMap":179},[183,1379,1380],{"class":185,"line":186},[183,1381,547],{},[183,1383,1384],{"class":185,"line":192},[183,1385,189],{},[183,1387,1388],{"class":185,"line":199},[183,1389,196],{"emptyLinePlaceholder":195},[183,1391,1392],{"class":185,"line":205},[183,1393,560],{},[183,1395,1396],{"class":185,"line":211},[183,1397,1398],{},"def exclusive_mock():\n",[183,1400,1401],{"class":185,"line":217},[183,1402,570],{},[183,1404,1405],{"class":185,"line":222},[183,1406,1407],{}," yield m\n",[183,1409,1410],{"class":185,"line":228},[183,1411,1412],{}," # Post-test validation\n",[183,1414,1415],{"class":185,"line":234},[183,1416,1417],{}," if m.side_effect is not None and m.return_value is not None:\n",[183,1419,1420],{"class":185,"line":368},[183,1421,1422],{}," raise AssertionError(\"Mutual exclusivity violated: both side_effect and return_value are set.\")\n",[183,1424,1425],{"class":185,"line":374},[183,1426,1427],{}," m.reset_mock()\n",[183,1429,1430],{"class":185,"line":380},[183,1431,1432],{}," m.side_effect = None\n",[183,1434,1435],{"class":185,"line":386},[183,1436,1437],{}," m.return_value = None\n",[14,1439,1440],{},"This pattern guarantees that test teardown validates configuration integrity, catching precedence violations before they propagate to subsequent test runs.",[45,1442,1444],{"id":1443},"integrating-with-pytest-and-hypothesis","Integrating with pytest and Hypothesis",[14,1446,1447,1448,1451,1452,33,1454,1456],{},"Property-based testing with ",[18,1449,1450],{},"hypothesis"," exposes edge cases that deterministic fixtures miss. By generating random ",[18,1453,32],{},[18,1455,36],{}," combinations, you can verify that mock dispatch remains deterministic under stress.",[174,1458,1460],{"className":176,"code":1459,"language":178,"meta":179,"style":179},"from hypothesis import given, strategies as st, settings\nimport unittest.mock\nimport pytest\n\n@given(\n side_effect=st.one_of(st.none(), st.integers(), st.lists(st.integers(max_size=5))),\n return_value=st.integers()\n)\n@settings(max_examples=200)\ndef test_mock_precedence_determinism(side_effect, return_value):\n m = unittest.mock.Mock(side_effect=side_effect, return_value=return_value)\n try:\n res = m()\n # If side_effect is None, return_value must be returned\n if side_effect is None:\n assert res == return_value\n # If side_effect is an int, it's returned directly\n elif isinstance(side_effect, int):\n assert res == side_effect\n # If side_effect is a list, it yields sequentially\n elif isinstance(side_effect, list):\n assert res in side_effect\n except StopIteration:\n # Expected when iterable is exhausted\n pass\n",[18,1461,1462,1467,1471,1475,1479,1484,1489,1494,1498,1503,1508,1513,1517,1522,1527,1532,1537,1542,1547,1552,1557,1562,1567,1571,1576],{"__ignoreMap":179},[183,1463,1464],{"class":185,"line":186},[183,1465,1466],{},"from hypothesis import given, strategies as st, settings\n",[183,1468,1469],{"class":185,"line":192},[183,1470,189],{},[183,1472,1473],{"class":185,"line":199},[183,1474,547],{},[183,1476,1477],{"class":185,"line":205},[183,1478,196],{"emptyLinePlaceholder":195},[183,1480,1481],{"class":185,"line":211},[183,1482,1483],{},"@given(\n",[183,1485,1486],{"class":185,"line":217},[183,1487,1488],{}," side_effect=st.one_of(st.none(), st.integers(), st.lists(st.integers(max_size=5))),\n",[183,1490,1491],{"class":185,"line":222},[183,1492,1493],{}," return_value=st.integers()\n",[183,1495,1496],{"class":185,"line":228},[183,1497,1333],{},[183,1499,1500],{"class":185,"line":234},[183,1501,1502],{},"@settings(max_examples=200)\n",[183,1504,1505],{"class":185,"line":368},[183,1506,1507],{},"def test_mock_precedence_determinism(side_effect, return_value):\n",[183,1509,1510],{"class":185,"line":374},[183,1511,1512],{}," m = unittest.mock.Mock(side_effect=side_effect, return_value=return_value)\n",[183,1514,1515],{"class":185,"line":380},[183,1516,925],{},[183,1518,1519],{"class":185,"line":386},[183,1520,1521],{}," res = m()\n",[183,1523,1524],{"class":185,"line":392},[183,1525,1526],{}," # If side_effect is None, return_value must be returned\n",[183,1528,1529],{"class":185,"line":398},[183,1530,1531],{}," if side_effect is None:\n",[183,1533,1534],{"class":185,"line":404},[183,1535,1536],{}," assert res == return_value\n",[183,1538,1539],{"class":185,"line":410},[183,1540,1541],{}," # If side_effect is an int, it's returned directly\n",[183,1543,1544],{"class":185,"line":416},[183,1545,1546],{}," elif isinstance(side_effect, int):\n",[183,1548,1549],{"class":185,"line":421},[183,1550,1551],{}," assert res == side_effect\n",[183,1553,1554],{"class":185,"line":427},[183,1555,1556],{}," # If side_effect is a list, it yields sequentially\n",[183,1558,1559],{"class":185,"line":433},[183,1560,1561],{}," elif isinstance(side_effect, list):\n",[183,1563,1564],{"class":185,"line":438},[183,1565,1566],{}," assert res in side_effect\n",[183,1568,1569],{"class":185,"line":443},[183,1570,935],{},[183,1572,1573],{"class":185,"line":449},[183,1574,1575],{}," # Expected when iterable is exhausted\n",[183,1577,1578],{"class":185,"line":454},[183,1579,1580],{}," pass\n",[14,1582,1583,1584,1586],{},"To automate validation across an entire test suite, implement a ",[18,1585,271],{}," plugin hook that inspects mock configurations at setup:",[174,1588,1590],{"className":176,"code":1589,"language":178,"meta":179,"style":179},"# conftest.py\nimport pytest\nimport unittest.mock\n\ndef pytest_runtest_setup(item):\n for fixture in item.funcargs.values():\n if isinstance(fixture, unittest.mock.Mock):\n if fixture.side_effect is not None and fixture.return_value is not None:\n raise pytest.fail(\n f\"Test {item.nodeid} violates mock exclusivity. \"\n \"Clear either side_effect or return_value before execution.\"\n )\n",[18,1591,1592,1597,1601,1605,1609,1614,1619,1624,1629,1634,1639,1644],{"__ignoreMap":179},[183,1593,1594],{"class":185,"line":186},[183,1595,1596],{},"# conftest.py\n",[183,1598,1599],{"class":185,"line":192},[183,1600,547],{},[183,1602,1603],{"class":185,"line":199},[183,1604,189],{},[183,1606,1607],{"class":185,"line":205},[183,1608,196],{"emptyLinePlaceholder":195},[183,1610,1611],{"class":185,"line":211},[183,1612,1613],{},"def pytest_runtest_setup(item):\n",[183,1615,1616],{"class":185,"line":217},[183,1617,1618],{}," for fixture in item.funcargs.values():\n",[183,1620,1621],{"class":185,"line":222},[183,1622,1623],{}," if isinstance(fixture, unittest.mock.Mock):\n",[183,1625,1626],{"class":185,"line":228},[183,1627,1628],{}," if fixture.side_effect is not None and fixture.return_value is not None:\n",[183,1630,1631],{"class":185,"line":234},[183,1632,1633],{}," raise pytest.fail(\n",[183,1635,1636],{"class":185,"line":368},[183,1637,1638],{}," f\"Test {item.nodeid} violates mock exclusivity. \"\n",[183,1640,1641],{"class":185,"line":374},[183,1642,1643],{}," \"Clear either side_effect or return_value before execution.\"\n",[183,1645,1646],{"class":185,"line":380},[183,1647,1648],{}," )\n",[14,1650,1651,1652,1654],{},"This hook intercepts test setup, failing fast if conflicting attributes are detected. Combined with ",[18,1653,1450],{}," fuzzing, it creates a robust safety net that catches precedence violations before they reach CI pipelines.",[45,1656,1658],{"id":1657},"frequently-asked-questions","Frequently Asked Questions",[14,1660,1661,1673,1674,1677,1678,1680,1681,1683,1684,1686,1687,1689],{},[84,1662,1663,1664,1666,1667,1669,1670,1672],{},"Does setting ",[18,1665,32],{}," to ",[18,1668,20],{}," restore ",[18,1671,36],{}," behavior?","\nYes, explicitly assigning ",[18,1675,1676],{},"side_effect = None"," clears the override and restores ",[18,1679,36],{}," dispatch. However, if the mock was previously exhausted as an iterator, you must also reset the internal iterator state or call ",[18,1682,1347],{}," to avoid residual ",[18,1685,24],{}," exceptions. The precedence chain only checks ",[18,1688,32],{}," at call time, but exhausted iterables retain their internal cursor.",[14,1691,1692,1704,1706,1707,1172,1710,1713,1714,1716,1717,1719,1720,1722,1723,1725,1726,1729,1730,136],{},[84,1693,1694,1695,1697,1698,1700,1701,1703],{},"Why does my ",[18,1696,901],{}," return ",[18,1699,20],{}," despite ",[18,1702,36],{}," being set?",[18,1705,901],{}," magic method attributes (e.g., ",[18,1708,1709],{},"mock.__getitem__",[18,1711,1712],{},"mock.__iter__",") inherit from the parent mock. If the parent has a ",[18,1715,32],{}," that returns ",[18,1718,20],{}," or raises an exception, child magic methods will bypass ",[18,1721,36],{},". Use ",[18,1724,1186],{}," or explicitly configure child mocks to isolate behavior. Additionally, ensure you are not accidentally calling ",[18,1727,1728],{},"mock()"," instead of ",[18,1731,1732],{},"mock.method()",[14,1734,1735,1743,1744,1746,1747,1749,1750,1752,1753,1755,1756,1758,1759,1761],{},[84,1736,1737,1738,33,1740,1742],{},"Can ",[18,1739,32],{},[18,1741,36],{}," be used simultaneously?","\nNo. The ",[18,1745,75],{}," implementation evaluates ",[18,1748,32],{}," first. If ",[18,1751,32],{}," is truthy (callable, iterable, or exception), ",[18,1754,36],{}," is completely ignored for that invocation. To combine behaviors, wrap ",[18,1757,36],{}," inside a callable ",[18,1760,32],{}," that conditionally returns it based on input arguments or internal state.",[14,1763,1764,1767,1768,1770,1771,1773,1774,1776,1777,1780,1781,1783,1784,1787,1788,958,1790,1792],{},[84,1765,1766],{},"How do I profile mock dispatch overhead in large test suites?","\nUse ",[18,1769,967],{}," with a custom ",[18,1772,784],{}," subclass that wraps ",[18,1775,57],{}," in ",[18,1778,1779],{},"time.perf_counter_ns()",". Alternatively, run ",[18,1782,971],{}," on the test module and filter for ",[18,1785,1786],{},"unittest.mock.*"," calls. High overhead usually indicates deeply nested ",[18,1789,32],{},[18,1791,284],{}," inspection. Isolate the overhead by benchmarking raw attribute lookup versus actual callable execution in high",[1794,1795,1796],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":179,"searchDepth":192,"depth":192,"links":1798},[1799,1800,1801,1806,1807,1808,1809,1810],{"id":47,"depth":192,"text":48},{"id":251,"depth":192,"text":252},{"id":525,"depth":192,"text":526,"children":1802},[1803,1804,1805],{"id":536,"depth":199,"text":537},{"id":620,"depth":199,"text":621},{"id":683,"depth":199,"text":684},{"id":774,"depth":192,"text":775},{"id":951,"depth":192,"text":952},{"id":1246,"depth":192,"text":1247},{"id":1443,"depth":192,"text":1444},{"id":1657,"depth":192,"text":1658},"Flaky test suites, silent None returns, and unexpected StopIteration exceptions frequently trace back to a single root cause: misconfigured unittest.mock.Mock objects where side_effect and return_value compete for dispatch priority. In production-grade Python testing, understanding the exact attribute resolution order, state mutation traps, and framework-level scoping rules is non-negotiable. This guide provides a deterministic workflow for diagnosing, isolating, and permanently resolving side_effect vs return_value conflicts across synchronous, asynchronous, and property-based testing paradigms.","md",{},"\u002Fadvanced-mocking-test-doubles-in-python\u002Fautospec-strict-mocking\u002Fresolving-side_effect-and-return_value-conflicts",{"title":5,"description":1811},"advanced-mocking-test-doubles-in-python\u002Fautospec-strict-mocking\u002Fresolving-side_effect-and-return_value-conflicts\u002Findex","nbZvICwbl3XBOSqi_kGAk9uF5yiZW-vWesYhviGEM-0",1778004578949]