@@ -2782,3 +2782,123 @@ Sealing mocks
27822782 >>> mock.not_submock.attribute2 # This won't raise.
27832783
27842784 .. versionadded :: 3.7
2785+
2786+
2787+ Order of precedence of :attr: `side_effect `, :attr: `return_value ` and *wraps *
2788+ ----------------------------------------------------------------------------
2789+
2790+ The order of their precedence is:
2791+
2792+ 1. :attr: `~Mock.side_effect `
2793+ 2. :attr: `~Mock.return_value `
2794+ 3. *wraps *
2795+
2796+ If all three are set, mock will return the value from :attr: `~Mock.side_effect `,
2797+ ignoring :attr: `~Mock.return_value ` and the wrapped object altogether. If any
2798+ two are set, the one with the higher precedence will return the value.
2799+ Regardless of the order of which was set first, the order of precedence
2800+ remains unchanged.
2801+
2802+ >>> from unittest.mock import Mock
2803+ >>> class Order :
2804+ ... @ staticmethod
2805+ ... def get_value ():
2806+ ... return " third"
2807+ ...
2808+ >>> order_mock = Mock(spec = Order, wraps = Order)
2809+ >>> order_mock.get_value.side_effect = [" first" ]
2810+ >>> order_mock.get_value.return_value = " second"
2811+ >>> order_mock.get_value()
2812+ 'first'
2813+
2814+ As ``None `` is the default value of :attr: `~Mock.side_effect `, if you reassign
2815+ its value back to ``None ``, the order of precedence will be checked between
2816+ :attr: `~Mock.return_value ` and the wrapped object, ignoring
2817+ :attr: `~Mock.side_effect `.
2818+
2819+ >>> order_mock.get_value.side_effect = None
2820+ >>> order_mock.get_value()
2821+ 'second'
2822+
2823+ If the value being returned by :attr: `~Mock.side_effect ` is :data: `DEFAULT `,
2824+ it is ignored and the order of precedence moves to the successor to obtain the
2825+ value to return.
2826+
2827+ >>> from unittest.mock import DEFAULT
2828+ >>> order_mock.get_value.side_effect = [DEFAULT ]
2829+ >>> order_mock.get_value()
2830+ 'second'
2831+
2832+ When :class: `Mock ` wraps an object, the default value of
2833+ :attr: `~Mock.return_value ` will be :data: `DEFAULT `.
2834+
2835+ >>> order_mock = Mock(spec = Order, wraps = Order)
2836+ >>> order_mock.return_value
2837+ sentinel.DEFAULT
2838+ >>> order_mock.get_value.return_value
2839+ sentinel.DEFAULT
2840+
2841+ The order of precedence will ignore this value and it will move to the last
2842+ successor which is the wrapped object.
2843+
2844+ As the real call is being made to the wrapped object, creating an instance of
2845+ this mock will return the real instance of the class. The positional arguments,
2846+ if any, required by the wrapped object must be passed.
2847+
2848+ >>> order_mock_instance = order_mock()
2849+ >>> isinstance (order_mock_instance, Order)
2850+ True
2851+ >>> order_mock_instance.get_value()
2852+ 'third'
2853+
2854+ >>> order_mock.get_value.return_value = DEFAULT
2855+ >>> order_mock.get_value()
2856+ 'third'
2857+
2858+ >>> order_mock.get_value.return_value = " second"
2859+ >>> order_mock.get_value()
2860+ 'second'
2861+
2862+ But if you assign ``None `` to it, this will not be ignored as it is an
2863+ explicit assignment. So, the order of precedence will not move to the wrapped
2864+ object.
2865+
2866+ >>> order_mock.get_value.return_value = None
2867+ >>> order_mock.get_value() is None
2868+ True
2869+
2870+ Even if you set all three at once when initializing the mock, the order of
2871+ precedence remains the same:
2872+
2873+ >>> order_mock = Mock(spec = Order, wraps = Order,
2874+ ... ** {" get_value.side_effect" : [" first" ],
2875+ ... " get_value.return_value" : " second" }
2876+ ... )
2877+ ...
2878+ >>> order_mock.get_value()
2879+ 'first'
2880+ >>> order_mock.get_value.side_effect = None
2881+ >>> order_mock.get_value()
2882+ 'second'
2883+ >>> order_mock.get_value.return_value = DEFAULT
2884+ >>> order_mock.get_value()
2885+ 'third'
2886+
2887+ If :attr: `~Mock.side_effect ` is exhausted, the order of precedence will not
2888+ cause a value to be obtained from the successors. Instead, ``StopIteration ``
2889+ exception is raised.
2890+
2891+ >>> order_mock = Mock(spec = Order, wraps = Order)
2892+ >>> order_mock.get_value.side_effect = [" first side effect value" ,
2893+ ... " another side effect value" ]
2894+ >>> order_mock.get_value.return_value = " second"
2895+
2896+ >>> order_mock.get_value()
2897+ 'first side effect value'
2898+ >>> order_mock.get_value()
2899+ 'another side effect value'
2900+
2901+ >>> order_mock.get_value()
2902+ Traceback (most recent call last):
2903+ ...
2904+ StopIteration
0 commit comments