Codebase list python-mockito / b43dd807-0d62-46ec-bf3e-a12aed757cde/upstream
Import upstream version 1.2.2 Kali Janitor 3 years ago
9 changed file(s) with 222 addition(s) and 32 deletion(s). Raw diff Collapse all Expand all
00 [bumpversion]
1 current_version = 1.2.0
1 current_version = 1.2.2
22 commit = True
33 message = Bump version to {new_version}
44 tag = True
00 MOCKITO CHANGE LOG
11 ==================
2
3 Release 1.2.2 (September 9, 2020)
4 ---------------------------------
5
6 - Fix typo in ``spy2`` doc
7
8
9 Release 1.2.1 (February 19, 2020)
10 ---------------------------------
11
12 - @nielsvaneck fixed how we can lookup inherited classmethods.
13
214
315 Release 1.2.0 (November 25, 2019)
416 ---------------------------------
719 - Fine tune error messages on unexpected calls or verifications. E.g. if you expect ``when(dog).bark('Wuff')`` but on call time do ``dog.bark('Wufff')``. Likewise, if you call ``dog.bark('Miau')`` and then ``verify(dog).bark('Maui')``.
820 - @felixonmars fixed a small compatibility issue with python 3.8
921 - Mocking properties has become a bit easier. (#26) E.g.
10
22
1123 prop = mock()
1224 when(m).__get__(...).thenReturn(23)
1325 m = mock({'name': prop})
14
26
1527
1628 Release 1.1.1 (August 28, 2018)
1729 -------------------------------
2840 - Added ``forget_invocations`` function. Thanks to @maximkulkin
2941
3042 This is generally useful if you already call mocks during your setup routine.
31 Now you could call ``forget_invocations`` at the end of your setup, and
43 Now you could call ``forget_invocations`` at the end of your setup, and
3244 have a clean 'recording' for your actual test code. T.i. you don't have
3345 to count the invocations from your setup code anymore.
3446
0 bumpversion release --tag
1 bumpversion patch --no-tag --message "master is {new_version}"
0 bump2version release --tag
1 bump2version patch --no-tag --message "master is {new_version}"
1212
1313 So in difference to traditional patching, in mockito you always specify concrete arguments (a call signature), and its outcome, usually a return value via `thenReturn` or a raised exception via `thenRaise`. That effectively turns function calls into constants for the time of the test.
1414
15 Do **not** forget to :func:`unstub` of course!
15 There are of course reasons when you don't want to overspecify specific tests. You _just_ want the desired stub answer. Here we go::
16
17 when(os.path).exists(...).thenReturn(True)
18
19 # now, obviously, you get the same answer, regardless of the arguments
20 os.path.exists('FooBar') # => True
21
22 You can combine both stubs. E.g. nothing exists, except one file::
23
24 when(os.path).exists(...).thenReturn(False)
25 when(os.path).exists('.flake8').thenReturn(True)
26
27 And because it's a similar pattern, we can introduce :func:`spy2` here. Spies call through the original implementation of a given function. E.g. everything is as it is, except `'.flake8'` is just not there::
28
29 from mockito import spy2
30 spy2(os.path.exists)
31 when(os.path).exists('.flake8').thenReturn(False)
32
33 When patching, you **MUST** **not** forget to :func:`unstub` of course! You can do this explicitly
1634
1735 ::
1836
1937 from mockito import unstub
2038 unstub() # restore os.path module
2139
22
23 Now we mix global module patching with mocks. We want to test the following function using the fab `requests` library::
40 Usually you do this unconditionally in your `teardown` function. If you're using `pytest`, you could define a fixture instead
41
42 ::
43 # conftest.py
44 import pytest
45
46 @pytest.fixture
47 def unstub():
48 from mockito import unstub
49 yield
50 unstub()
51
52 # my_test.py
53 import pytest
54 pytestmark = pytest.mark.usefixtures("unstub")
55
56 But very often you just use context managers (aka `with`), and mockito will unstub on 'exit' automatically::
57
58 # E.g. test that `exists` gets never called
59 with expect(os.path, times=0).exists('.flake8'):
60 # within the block `os.path.exists` is patched
61 cached_dir_lookup('.flake8')
62 # at the end of the block `os.path` gets unpatched
63
64 # Which is btw roughly the same as doing
65 with when(os.path).exists('.flake8'):
66 cached_dir_lookup('.flake8')
67 verify(os.path, times=0).exists(...)
68
69 Now let's mix global module patching with mocks. We want to test the following function using the fab `requests` library::
2470
2571 import requests
2672
4343 from .matchers import any, contains, times
4444 from .verification import never
4545
46 __version__ = '1.2.0'
46 __version__ = '1.2.2'
4747
4848 __all__ = [
4949 'mock',
1717 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1818 # THE SOFTWARE.
1919
20 import functools
21 import inspect
22 import operator
2023 from collections import deque
21 import inspect
22 import functools
23 import operator
24
25 from . import invocation
26 from . import signature
27 from . import utils
24
25 from . import invocation, signature, utils
2826 from .mock_registry import mock_registry
29
3027
3128 __all__ = ['mock']
3229
7471 # STUBBING
7572
7673 def get_original_method(self, method_name):
74 """
75 Looks up the original method on the `spec` object and returns it
76 together with an indication of whether the method is found
77 "directly" on the `spec` object.
78
79 This is used to decide whether the method should be stored as an
80 original_method and should therefore be replaced when unstubbing.
81 """
7782 if self.spec is None:
78 return None
83 return None, False
7984
8085 try:
81 return self.spec.__dict__.get(method_name)
82 except AttributeError:
83 return getattr(self.spec, method_name, None)
86 return self.spec.__dict__[method_name], True
87 except (AttributeError, KeyError):
88 # Classes with defined `__slots__` and then no `__dict__` are not
89 # patchable but if we catch the `AttributeError` here, we get
90 # the better error message for the user.
91 return getattr(self.spec, method_name, None), False
8492
8593 def set_method(self, method_name, new_method):
8694 setattr(self.mocked_obj, method_name, new_method)
129137 try:
130138 self.original_methods[method_name]
131139 except KeyError:
132 original_method = self.get_original_method(method_name)
133 self.original_methods[method_name] = original_method
140 original_method, was_in_spec = self.get_original_method(
141 method_name)
142 if was_in_spec:
143 # This indicates the original method was found directly on
144 # the spec object and should therefore be restored by unstub
145 self.original_methods[method_name] = original_method
146 else:
147 self.original_methods[method_name] = None
134148
135149 self.replace_method(method_name, original_method)
136150
231245 `when`::
232246
233247 dummy = mock()
234 when(dummy).__call_(1).thenReturn(2)
248 when(dummy).__call__(1).thenReturn(2)
235249
236250 All other magic methods must be configured this way or they will raise an
237251 AttributeError.
8787 E.g.::
8888
8989 import time
90 spy(time.time)
90 spy2(time.time)
9191 do_work(...) # nothing injected, uses global patched `time` module
9292 verify(time).time()
9393
1313
1414
1515 def newmethod(fn, obj):
16 if PY3:
17 return types.MethodType(fn, obj)
18 else:
19 return types.MethodType(fn, obj, obj.__class__)
16 return types.MethodType(fn, obj)
2017
2118
2219 def get_function_host(fn):
1717 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1818 # THE SOFTWARE.
1919
20 from mockito import unstub, verify, when
21 from mockito.verification import VerificationError
22
2023 from .test_base import TestBase
21 from mockito import when, unstub, verify
22 from mockito.verification import VerificationError
24
2325
2426 class Dog:
2527 @classmethod
104106 self.assertEqual("Cat foo", Cat.meow("foo"))
105107
106108
109 class Retriever:
110 @classmethod
111 def retrieve(cls, item):
112 return item
113
114
115 class TrickDog(Dog, Retriever):
116 pass
117
118
119 class InheritedClassMethodsTest(TestBase):
120
121 def tearDown(self):
122 unstub()
123
124 def testUnstubs(self):
125 when(TrickDog).bark().thenReturn("miau!")
126 when(TrickDog).retrieve("stick").thenReturn("ball")
127 unstub()
128 self.assertEqual("woof!", TrickDog.bark())
129 self.assertEqual("stick", TrickDog.retrieve("stick"))
130
131 def testStubs(self):
132 self.assertEqual("woof!", TrickDog.bark())
133 self.assertEqual("stick", TrickDog.retrieve("stick"))
134
135 when(TrickDog).bark().thenReturn("miau!")
136 when(TrickDog).retrieve("stick").thenReturn("ball")
137
138 self.assertEqual("miau!", TrickDog.bark())
139 self.assertEqual("ball", TrickDog.retrieve("stick"))
140
141 def testVerifiesMultipleCallsOnClassmethod(self):
142 when(TrickDog).bark().thenReturn("miau!")
143 when(TrickDog).retrieve("stick").thenReturn("ball")
144
145 TrickDog.bark()
146 TrickDog.bark()
147
148 TrickDog.retrieve("stick")
149 TrickDog.retrieve("stick")
150
151 verify(TrickDog, times=2).bark()
152 verify(TrickDog, times=2).retrieve("stick")
153
154 def testFailsVerificationOfMultipleCallsOnClassmethod(self):
155 when(TrickDog).bark().thenReturn("miau!")
156 when(TrickDog).retrieve("stick").thenReturn("bark")
157
158 TrickDog.bark()
159 TrickDog.retrieve("stick")
160
161 self.assertRaises(VerificationError, verify(TrickDog, times=2).bark)
162 self.assertRaises(VerificationError, verify(TrickDog,
163 times=2).retrieve)
164
165 def testStubsAndVerifiesClassmethod(self):
166 when(TrickDog).bark().thenReturn("miau!")
167 when(TrickDog).retrieve("stick").thenReturn("ball")
168
169 self.assertEqual("miau!", TrickDog.bark())
170 self.assertEqual("ball", TrickDog.retrieve("stick"))
171
172 verify(TrickDog).bark()
173 verify(TrickDog).retrieve("stick")
174
175 def testPreservesSuperClassClassMethodWhenStubbed(self):
176 self.assertEqual("woof!", Dog.bark())
177 self.assertEqual("stick", Retriever.retrieve("stick"))
178
179 self.assertEqual("woof!", TrickDog.bark())
180 self.assertEqual("stick", TrickDog.retrieve("stick"))
181
182 when(TrickDog).bark().thenReturn("miau!")
183 when(TrickDog).retrieve("stick").thenReturn("ball")
184
185 self.assertEqual("miau!", TrickDog.bark())
186 self.assertEqual("ball", TrickDog.retrieve("stick"))
187
188 self.assertEqual("woof!", Dog.bark())
189 self.assertEqual("stick", Retriever.retrieve("stick"))
190
191 def testDoubleStubStubWorksAfterUnstub(self):
192 when(TrickDog).retrieve("stick").thenReturn("ball")
193 when(TrickDog).retrieve("stick").thenReturn("cat")
194 unstub()
195 self.assertEqual("stick", TrickDog.retrieve("stick"))
196
197 def testUnStubWorksOnClassAndSuperClass(self):
198 self.assertEqual("stick", Retriever.retrieve("stick"))
199 self.assertEqual("stick", TrickDog.retrieve("stick"))
200
201 when(Retriever).retrieve("stick").thenReturn("ball")
202 self.assertEqual("ball", Retriever.retrieve("stick"))
203 self.assertEqual("ball", TrickDog.retrieve("stick"))
204
205 when(TrickDog).retrieve("stick").thenReturn("cat")
206 self.assertEqual("ball", Retriever.retrieve("stick"))
207 self.assertEqual("cat", TrickDog.retrieve("stick"))
208
209 unstub(TrickDog)
210 self.assertEqual("ball", Retriever.retrieve("stick"))
211 self.assertEqual("ball", TrickDog.retrieve("stick"))
212
213 unstub(Retriever)
214 self.assertEqual("stick", Retriever.retrieve("stick"))
215 self.assertEqual("stick", TrickDog.retrieve("stick"))
216
217 def testReverseOrderWhenUnstubbing(self):
218 when(Retriever).retrieve("stick").thenReturn("ball")
219 when(TrickDog).retrieve("stick").thenReturn("cat")
220
221 unstub(Retriever)
222 self.assertEqual("stick", Retriever.retrieve("stick"))
223 self.assertEqual("cat", TrickDog.retrieve("stick"))
224
225 unstub(TrickDog)
226 self.assertEqual("stick", Retriever.retrieve("stick"))
227 self.assertEqual("stick", TrickDog.retrieve("stick"))