@@ -2831,3 +2831,123 @@ Sealing mocks
2831
2831
>>> mock.not_submock.attribute2 # This won't raise.
2832
2832
2833
2833
.. versionadded :: 3.7
2834
+
2835
+
2836
+ Order of precedence of :attr: `side_effect `, :attr: `return_value ` and *wraps *
2837
+ ----------------------------------------------------------------------------
2838
+
2839
+ The order of their precedence is:
2840
+
2841
+ 1. :attr: `~Mock.side_effect `
2842
+ 2. :attr: `~Mock.return_value `
2843
+ 3. *wraps *
2844
+
2845
+ If all three are set, mock will return the value from :attr: `~Mock.side_effect `,
2846
+ ignoring :attr: `~Mock.return_value ` and the wrapped object altogether. If any
2847
+ two are set, the one with the higher precedence will return the value.
2848
+ Regardless of the order of which was set first, the order of precedence
2849
+ remains unchanged.
2850
+
2851
+ >>> from unittest.mock import Mock
2852
+ >>> class Order :
2853
+ ... @ staticmethod
2854
+ ... def get_value ():
2855
+ ... return " third"
2856
+ ...
2857
+ >>> order_mock = Mock(spec = Order, wraps = Order)
2858
+ >>> order_mock.get_value.side_effect = [" first" ]
2859
+ >>> order_mock.get_value.return_value = " second"
2860
+ >>> order_mock.get_value()
2861
+ 'first'
2862
+
2863
+ As ``None `` is the default value of :attr: `~Mock.side_effect `, if you reassign
2864
+ its value back to ``None ``, the order of precedence will be checked between
2865
+ :attr: `~Mock.return_value ` and the wrapped object, ignoring
2866
+ :attr: `~Mock.side_effect `.
2867
+
2868
+ >>> order_mock.get_value.side_effect = None
2869
+ >>> order_mock.get_value()
2870
+ 'second'
2871
+
2872
+ If the value being returned by :attr: `~Mock.side_effect ` is :data: `DEFAULT `,
2873
+ it is ignored and the order of precedence moves to the successor to obtain the
2874
+ value to return.
2875
+
2876
+ >>> from unittest.mock import DEFAULT
2877
+ >>> order_mock.get_value.side_effect = [DEFAULT ]
2878
+ >>> order_mock.get_value()
2879
+ 'second'
2880
+
2881
+ When :class: `Mock ` wraps an object, the default value of
2882
+ :attr: `~Mock.return_value ` will be :data: `DEFAULT `.
2883
+
2884
+ >>> order_mock = Mock(spec = Order, wraps = Order)
2885
+ >>> order_mock.return_value
2886
+ sentinel.DEFAULT
2887
+ >>> order_mock.get_value.return_value
2888
+ sentinel.DEFAULT
2889
+
2890
+ The order of precedence will ignore this value and it will move to the last
2891
+ successor which is the wrapped object.
2892
+
2893
+ As the real call is being made to the wrapped object, creating an instance of
2894
+ this mock will return the real instance of the class. The positional arguments,
2895
+ if any, required by the wrapped object must be passed.
2896
+
2897
+ >>> order_mock_instance = order_mock()
2898
+ >>> isinstance (order_mock_instance, Order)
2899
+ True
2900
+ >>> order_mock_instance.get_value()
2901
+ 'third'
2902
+
2903
+ >>> order_mock.get_value.return_value = DEFAULT
2904
+ >>> order_mock.get_value()
2905
+ 'third'
2906
+
2907
+ >>> order_mock.get_value.return_value = " second"
2908
+ >>> order_mock.get_value()
2909
+ 'second'
2910
+
2911
+ But if you assign ``None `` to it, this will not be ignored as it is an
2912
+ explicit assignment. So, the order of precedence will not move to the wrapped
2913
+ object.
2914
+
2915
+ >>> order_mock.get_value.return_value = None
2916
+ >>> order_mock.get_value() is None
2917
+ True
2918
+
2919
+ Even if you set all three at once when initializing the mock, the order of
2920
+ precedence remains the same:
2921
+
2922
+ >>> order_mock = Mock(spec = Order, wraps = Order,
2923
+ ... ** {" get_value.side_effect" : [" first" ],
2924
+ ... " get_value.return_value" : " second" }
2925
+ ... )
2926
+ ...
2927
+ >>> order_mock.get_value()
2928
+ 'first'
2929
+ >>> order_mock.get_value.side_effect = None
2930
+ >>> order_mock.get_value()
2931
+ 'second'
2932
+ >>> order_mock.get_value.return_value = DEFAULT
2933
+ >>> order_mock.get_value()
2934
+ 'third'
2935
+
2936
+ If :attr: `~Mock.side_effect ` is exhausted, the order of precedence will not
2937
+ cause a value to be obtained from the successors. Instead, ``StopIteration ``
2938
+ exception is raised.
2939
+
2940
+ >>> order_mock = Mock(spec = Order, wraps = Order)
2941
+ >>> order_mock.get_value.side_effect = [" first side effect value" ,
2942
+ ... " another side effect value" ]
2943
+ >>> order_mock.get_value.return_value = " second"
2944
+
2945
+ >>> order_mock.get_value()
2946
+ 'first side effect value'
2947
+ >>> order_mock.get_value()
2948
+ 'another side effect value'
2949
+
2950
+ >>> order_mock.get_value()
2951
+ Traceback (most recent call last):
2952
+ ...
2953
+ StopIteration
0 commit comments