Imported Upstream version 0.5.2
Sophie Brun
9 years ago
0 | repo: 0e8bada2d1d2eb28679ee7920c9c95fa05db4ebe | |
1 | node: d3b0a975a8625b665bdf7f6c4d4b1ec27f1e24b2 | |
2 | branch: default | |
3 | tag: 0.5.2 |
0 | 4a4ca8ec1ca0bcdd11205df320ba4ea3cdc72d5b 0.2.0 | |
1 | 63c076ff10e19c0fb77e53c09efe6376955b8c51 0.3.0 | |
2 | 63c076ff10e19c0fb77e53c09efe6376955b8c51 0.3.0 | |
3 | 0bf762bb937824cbf4c75e266ff74a1cb818b46e 0.3.0 | |
4 | cd7b4c80c09115193180d6aa4cee72576a345c7d 0.3.1 | |
5 | e52bff1de3e4d6fafee503dd2fdb00a2816c863a 0.4.0 | |
6 | def475b558e18016d7570f08e67922495814a65f 0.5.0 | |
7 | c5bdbb0e08984b982d0af6d6a4e54fbda86f3157 0.5.1 | |
8 | c5bdbb0e08984b982d0af6d6a4e54fbda86f3157 0.5.1 | |
9 | 80720803749610fdc9eb776c31e6f1b479e05786 0.5.1 |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <projectDescription> | |
2 | <name>mockito-python</name> | |
3 | <comment></comment> | |
4 | <projects> | |
5 | </projects> | |
6 | <buildSpec> | |
7 | <buildCommand> | |
8 | <name>org.python.pydev.PyDevBuilder</name> | |
9 | <arguments> | |
10 | </arguments> | |
11 | </buildCommand> | |
12 | </buildSpec> | |
13 | <natures> | |
14 | <nature>org.python.pydev.pythonNature</nature> | |
15 | </natures> | |
16 | </projectDescription> |
0 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
1 | <?eclipse-pydev version="1.0"?> | |
2 | ||
3 | <pydev_project> | |
4 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.6</pydev_property> | |
5 | <pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">python</pydev_property> | |
6 | <pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH"> | |
7 | <path>/mockito-python</path> | |
8 | <path>/mockito-python/mockito</path> | |
9 | </pydev_pathproperty> | |
10 | </pydev_project> |
0 | MOCKITO CHANGE LOG | |
1 | ================== | |
2 | ||
3 | Release 0.5.1 (August 4, 2010) | |
4 | ------------------------------ | |
5 | BUG Fixes: | |
6 | - Fixed issue #9 [http://bitbucket.org/szczepiq/mockito-python/issue/9] : Generating stubs from classes caused method to be replaced in original classes. | |
7 | ||
8 | Release 0.5.0 (July 26, 2010) | |
9 | ----------------------------- | |
10 | API Changes: | |
11 | - Added possibility to spy on real objects. | |
12 | - Added "never" syntactic sugar for verifications. | |
13 | ||
14 | BUG Fixes: | |
15 | - Fixed issue with named arguments matching. | |
16 | ||
17 | Other Changes: | |
18 | - Python 2.7 support | |
19 | - Deprecated APIs now generate deprecation warnings. | |
20 | ||
21 | Release 0.4.0 (July 2, 2010) | |
22 | ---------------------------- | |
23 | API Changes: | |
24 | - Added possibility to verify invocations in order. | |
25 | ||
26 | BUG Fixes: | |
27 | - Fixed issue with installing mockito from egg without distribute installed. | |
28 | ||
29 | Release 0.3.1 | |
30 | ------------- | |
31 | Bug-fix release. | |
32 | Bug Fixes: | |
33 | - Fixed annoying issue #8 [http://bitbucket.org/szczepiq/mockito-python/issue/8] | |
34 | ||
35 | Release 0.3.0 | |
36 | ------------- | |
37 | API Changes: | |
38 | - Renamed mock creation method from "Mock" (upper "M") to "mock". Old name stays for compatibility until 1.0 release. | |
39 | Other Changes: | |
40 | - Official Python3 support via distutils + 2to3. | |
41 |
0 | Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | ||
2 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | of this software and associated documentation files (the "Software"), to deal | |
4 | in the Software without restriction, including without limitation the rights | |
5 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | copies of the Software, and to permit persons to whom the Software is | |
7 | furnished to do so, subject to the following conditions: | |
8 | ||
9 | The above copyright notice and this permission notice shall be included in | |
10 | all copies or substantial portions of the Software. | |
11 | ||
12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | THE SOFTWARE.⏎ |
0 | Mockito is a spying framework based on Java library with the same name. | |
1 | ||
2 | 1. To install: | |
3 | ||
4 | $ python setup.py install | |
5 | ||
6 | 2. To run all tests: | |
7 | ||
8 | $ python setup.py test | |
9 | ||
10 | 3. For more info, see: | |
11 | ||
12 | __ http://code.google.com/p/mockito-python/ | |
13 | ||
14 | Feel free to contribute more documentation or feedback! | |
15 | ||
16 | 4. Our user and developer discussion group is: | |
17 | ||
18 | __ http://groups.google.com/group/mockito-python | |
19 | ||
20 | 5. Mockito is licensed under the MIT license | |
21 | ||
22 | 6. Library was tested with the following Python versions: | |
23 | ||
24 | Python 2.4.6 | |
25 | Python 2.5.4 | |
26 | Python 2.6.1 | |
27 | Python 2.7 | |
28 | Python 3.1.2 | |
29 | ||
30 | 7. (Generated from mockito_demo_test.py) Basic usage: | |
31 | ||
32 | import unittest | |
33 | from mockito import mock, when, verify | |
34 | ||
35 | class DemoTest(unittest.TestCase): | |
36 | def testStubbing(self): | |
37 | # create a mock | |
38 | ourMock = mock() | |
39 | ||
40 | # stub it | |
41 | when(ourMock).getStuff("cool").thenReturn("cool stuff") | |
42 | ||
43 | # use the mock | |
44 | self.assertEqual("cool stuff", ourMock.getStuff("cool")) | |
45 | ||
46 | # what happens when you pass different argument? | |
47 | self.assertEqual(None, ourMock.getStuff("different argument")) | |
48 | ||
49 | def testVerification(self): | |
50 | # create a mock | |
51 | theMock = mock() | |
52 | ||
53 | # use the mock | |
54 | theMock.doStuff("cool") | |
55 | ||
56 | # verify the interactions. Method and parameters must match. Otherwise verification error. | |
57 | verify(theMock).doStuff("cool") | |
58 | ||
59 | ⏎ |
0 | #!python | |
1 | """Bootstrap distribute installation | |
2 | ||
3 | If you want to use setuptools in your package's setup.py, just include this | |
4 | file in the same directory with it, and add this to the top of your setup.py:: | |
5 | ||
6 | from distribute_setup import use_setuptools | |
7 | use_setuptools() | |
8 | ||
9 | If you want to require a specific version of setuptools, set a download | |
10 | mirror, or use an alternate download directory, you can do so by supplying | |
11 | the appropriate options to ``use_setuptools()``. | |
12 | ||
13 | This file can also be run as a script to install or upgrade setuptools. | |
14 | """ | |
15 | import os | |
16 | import sys | |
17 | import time | |
18 | import fnmatch | |
19 | import tempfile | |
20 | import tarfile | |
21 | from distutils import log | |
22 | ||
23 | try: | |
24 | from site import USER_SITE | |
25 | except ImportError: | |
26 | USER_SITE = None | |
27 | ||
28 | try: | |
29 | import subprocess | |
30 | ||
31 | def _python_cmd(*args): | |
32 | args = (sys.executable,) + args | |
33 | return subprocess.call(args) == 0 | |
34 | ||
35 | except ImportError: | |
36 | # will be used for python 2.3 | |
37 | def _python_cmd(*args): | |
38 | args = (sys.executable,) + args | |
39 | # quoting arguments if windows | |
40 | if sys.platform == 'win32': | |
41 | def quote(arg): | |
42 | if ' ' in arg: | |
43 | return '"%s"' % arg | |
44 | return arg | |
45 | args = [quote(arg) for arg in args] | |
46 | return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 | |
47 | ||
48 | DEFAULT_VERSION = "0.6.10" | |
49 | DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" | |
50 | SETUPTOOLS_FAKED_VERSION = "0.6c11" | |
51 | ||
52 | SETUPTOOLS_PKG_INFO = """\ | |
53 | Metadata-Version: 1.0 | |
54 | Name: setuptools | |
55 | Version: %s | |
56 | Summary: xxxx | |
57 | Home-page: xxx | |
58 | Author: xxx | |
59 | Author-email: xxx | |
60 | License: xxx | |
61 | Description: xxx | |
62 | """ % SETUPTOOLS_FAKED_VERSION | |
63 | ||
64 | ||
65 | def _install(tarball): | |
66 | # extracting the tarball | |
67 | tmpdir = tempfile.mkdtemp() | |
68 | log.warn('Extracting in %s', tmpdir) | |
69 | old_wd = os.getcwd() | |
70 | try: | |
71 | os.chdir(tmpdir) | |
72 | tar = tarfile.open(tarball) | |
73 | _extractall(tar) | |
74 | tar.close() | |
75 | ||
76 | # going in the directory | |
77 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) | |
78 | os.chdir(subdir) | |
79 | log.warn('Now working in %s', subdir) | |
80 | ||
81 | # installing | |
82 | log.warn('Installing Distribute') | |
83 | if not _python_cmd('setup.py', 'install'): | |
84 | log.warn('Something went wrong during the installation.') | |
85 | log.warn('See the error message above.') | |
86 | finally: | |
87 | os.chdir(old_wd) | |
88 | ||
89 | ||
90 | def _build_egg(egg, tarball, to_dir): | |
91 | # extracting the tarball | |
92 | tmpdir = tempfile.mkdtemp() | |
93 | log.warn('Extracting in %s', tmpdir) | |
94 | old_wd = os.getcwd() | |
95 | try: | |
96 | os.chdir(tmpdir) | |
97 | tar = tarfile.open(tarball) | |
98 | _extractall(tar) | |
99 | tar.close() | |
100 | ||
101 | # going in the directory | |
102 | subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) | |
103 | os.chdir(subdir) | |
104 | log.warn('Now working in %s', subdir) | |
105 | ||
106 | # building an egg | |
107 | log.warn('Building a Distribute egg in %s', to_dir) | |
108 | _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) | |
109 | ||
110 | finally: | |
111 | os.chdir(old_wd) | |
112 | # returning the result | |
113 | log.warn(egg) | |
114 | if not os.path.exists(egg): | |
115 | raise IOError('Could not build the egg.') | |
116 | ||
117 | ||
118 | def _do_download(version, download_base, to_dir, download_delay): | |
119 | egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' | |
120 | % (version, sys.version_info[0], sys.version_info[1])) | |
121 | if not os.path.exists(egg): | |
122 | tarball = download_setuptools(version, download_base, | |
123 | to_dir, download_delay) | |
124 | _build_egg(egg, tarball, to_dir) | |
125 | sys.path.insert(0, egg) | |
126 | import setuptools | |
127 | setuptools.bootstrap_install_from = egg | |
128 | ||
129 | ||
130 | def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, | |
131 | to_dir=os.curdir, download_delay=15, no_fake=True): | |
132 | # making sure we use the absolute path | |
133 | to_dir = os.path.abspath(to_dir) | |
134 | was_imported = 'pkg_resources' in sys.modules or \ | |
135 | 'setuptools' in sys.modules | |
136 | try: | |
137 | try: | |
138 | import pkg_resources | |
139 | if not hasattr(pkg_resources, '_distribute'): | |
140 | if not no_fake: | |
141 | _fake_setuptools() | |
142 | raise ImportError | |
143 | except ImportError: | |
144 | return _do_download(version, download_base, to_dir, download_delay) | |
145 | try: | |
146 | pkg_resources.require("distribute>="+version) | |
147 | return | |
148 | except pkg_resources.VersionConflict: | |
149 | e = sys.exc_info()[1] | |
150 | if was_imported: | |
151 | sys.stderr.write( | |
152 | "The required version of distribute (>=%s) is not available,\n" | |
153 | "and can't be installed while this script is running. Please\n" | |
154 | "install a more recent version first, using\n" | |
155 | "'easy_install -U distribute'." | |
156 | "\n\n(Currently using %r)\n" % (version, e.args[0])) | |
157 | sys.exit(2) | |
158 | else: | |
159 | del pkg_resources, sys.modules['pkg_resources'] # reload ok | |
160 | return _do_download(version, download_base, to_dir, | |
161 | download_delay) | |
162 | except pkg_resources.DistributionNotFound: | |
163 | return _do_download(version, download_base, to_dir, | |
164 | download_delay) | |
165 | finally: | |
166 | if not no_fake: | |
167 | _create_fake_setuptools_pkg_info(to_dir) | |
168 | ||
169 | def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, | |
170 | to_dir=os.curdir, delay=15): | |
171 | """Download distribute from a specified location and return its filename | |
172 | ||
173 | `version` should be a valid distribute version number that is available | |
174 | as an egg for download under the `download_base` URL (which should end | |
175 | with a '/'). `to_dir` is the directory where the egg will be downloaded. | |
176 | `delay` is the number of seconds to pause before an actual download | |
177 | attempt. | |
178 | """ | |
179 | # making sure we use the absolute path | |
180 | to_dir = os.path.abspath(to_dir) | |
181 | try: | |
182 | from urllib.request import urlopen | |
183 | except ImportError: | |
184 | from urllib2 import urlopen | |
185 | tgz_name = "distribute-%s.tar.gz" % version | |
186 | url = download_base + tgz_name | |
187 | saveto = os.path.join(to_dir, tgz_name) | |
188 | src = dst = None | |
189 | if not os.path.exists(saveto): # Avoid repeated downloads | |
190 | try: | |
191 | log.warn("Downloading %s", url) | |
192 | src = urlopen(url) | |
193 | # Read/write all in one block, so we don't create a corrupt file | |
194 | # if the download is interrupted. | |
195 | data = src.read() | |
196 | dst = open(saveto, "wb") | |
197 | dst.write(data) | |
198 | finally: | |
199 | if src: | |
200 | src.close() | |
201 | if dst: | |
202 | dst.close() | |
203 | return os.path.realpath(saveto) | |
204 | ||
205 | ||
206 | def _patch_file(path, content): | |
207 | """Will backup the file then patch it""" | |
208 | existing_content = open(path).read() | |
209 | if existing_content == content: | |
210 | # already patched | |
211 | log.warn('Already patched.') | |
212 | return False | |
213 | log.warn('Patching...') | |
214 | _rename_path(path) | |
215 | f = open(path, 'w') | |
216 | try: | |
217 | f.write(content) | |
218 | finally: | |
219 | f.close() | |
220 | return True | |
221 | ||
222 | ||
223 | def _same_content(path, content): | |
224 | return open(path).read() == content | |
225 | ||
226 | def _no_sandbox(function): | |
227 | def __no_sandbox(*args, **kw): | |
228 | try: | |
229 | from setuptools.sandbox import DirectorySandbox | |
230 | def violation(*args): | |
231 | pass | |
232 | DirectorySandbox._old = DirectorySandbox._violation | |
233 | DirectorySandbox._violation = violation | |
234 | patched = True | |
235 | except ImportError: | |
236 | patched = False | |
237 | ||
238 | try: | |
239 | return function(*args, **kw) | |
240 | finally: | |
241 | if patched: | |
242 | DirectorySandbox._violation = DirectorySandbox._old | |
243 | del DirectorySandbox._old | |
244 | ||
245 | return __no_sandbox | |
246 | ||
247 | @_no_sandbox | |
248 | def _rename_path(path): | |
249 | new_name = path + '.OLD.%s' % time.time() | |
250 | log.warn('Renaming %s into %s', path, new_name) | |
251 | os.rename(path, new_name) | |
252 | return new_name | |
253 | ||
254 | def _remove_flat_installation(placeholder): | |
255 | if not os.path.isdir(placeholder): | |
256 | log.warn('Unkown installation at %s', placeholder) | |
257 | return False | |
258 | found = False | |
259 | for file in os.listdir(placeholder): | |
260 | if fnmatch.fnmatch(file, 'setuptools*.egg-info'): | |
261 | found = True | |
262 | break | |
263 | if not found: | |
264 | log.warn('Could not locate setuptools*.egg-info') | |
265 | return | |
266 | ||
267 | log.warn('Removing elements out of the way...') | |
268 | pkg_info = os.path.join(placeholder, file) | |
269 | if os.path.isdir(pkg_info): | |
270 | patched = _patch_egg_dir(pkg_info) | |
271 | else: | |
272 | patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) | |
273 | ||
274 | if not patched: | |
275 | log.warn('%s already patched.', pkg_info) | |
276 | return False | |
277 | # now let's move the files out of the way | |
278 | for element in ('setuptools', 'pkg_resources.py', 'site.py'): | |
279 | element = os.path.join(placeholder, element) | |
280 | if os.path.exists(element): | |
281 | _rename_path(element) | |
282 | else: | |
283 | log.warn('Could not find the %s element of the ' | |
284 | 'Setuptools distribution', element) | |
285 | return True | |
286 | ||
287 | ||
288 | def _after_install(dist): | |
289 | log.warn('After install bootstrap.') | |
290 | placeholder = dist.get_command_obj('install').install_purelib | |
291 | _create_fake_setuptools_pkg_info(placeholder) | |
292 | ||
293 | @_no_sandbox | |
294 | def _create_fake_setuptools_pkg_info(placeholder): | |
295 | if not placeholder or not os.path.exists(placeholder): | |
296 | log.warn('Could not find the install location') | |
297 | return | |
298 | pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) | |
299 | setuptools_file = 'setuptools-%s-py%s.egg-info' % \ | |
300 | (SETUPTOOLS_FAKED_VERSION, pyver) | |
301 | pkg_info = os.path.join(placeholder, setuptools_file) | |
302 | if os.path.exists(pkg_info): | |
303 | log.warn('%s already exists', pkg_info) | |
304 | return | |
305 | ||
306 | log.warn('Creating %s', pkg_info) | |
307 | f = open(pkg_info, 'w') | |
308 | try: | |
309 | f.write(SETUPTOOLS_PKG_INFO) | |
310 | finally: | |
311 | f.close() | |
312 | ||
313 | pth_file = os.path.join(placeholder, 'setuptools.pth') | |
314 | log.warn('Creating %s', pth_file) | |
315 | f = open(pth_file, 'w') | |
316 | try: | |
317 | f.write(os.path.join(os.curdir, setuptools_file)) | |
318 | finally: | |
319 | f.close() | |
320 | ||
321 | def _patch_egg_dir(path): | |
322 | # let's check if it's already patched | |
323 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') | |
324 | if os.path.exists(pkg_info): | |
325 | if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): | |
326 | log.warn('%s already patched.', pkg_info) | |
327 | return False | |
328 | _rename_path(path) | |
329 | os.mkdir(path) | |
330 | os.mkdir(os.path.join(path, 'EGG-INFO')) | |
331 | pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') | |
332 | f = open(pkg_info, 'w') | |
333 | try: | |
334 | f.write(SETUPTOOLS_PKG_INFO) | |
335 | finally: | |
336 | f.close() | |
337 | return True | |
338 | ||
339 | ||
340 | def _before_install(): | |
341 | log.warn('Before install bootstrap.') | |
342 | _fake_setuptools() | |
343 | ||
344 | ||
345 | def _under_prefix(location): | |
346 | if 'install' not in sys.argv: | |
347 | return True | |
348 | args = sys.argv[sys.argv.index('install')+1:] | |
349 | for index, arg in enumerate(args): | |
350 | for option in ('--root', '--prefix'): | |
351 | if arg.startswith('%s=' % option): | |
352 | top_dir = arg.split('root=')[-1] | |
353 | return location.startswith(top_dir) | |
354 | elif arg == option: | |
355 | if len(args) > index: | |
356 | top_dir = args[index+1] | |
357 | return location.startswith(top_dir) | |
358 | elif option == '--user' and USER_SITE is not None: | |
359 | return location.startswith(USER_SITE) | |
360 | return True | |
361 | ||
362 | ||
363 | def _fake_setuptools(): | |
364 | log.warn('Scanning installed packages') | |
365 | try: | |
366 | import pkg_resources | |
367 | except ImportError: | |
368 | # we're cool | |
369 | log.warn('Setuptools or Distribute does not seem to be installed.') | |
370 | return | |
371 | ws = pkg_resources.working_set | |
372 | try: | |
373 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', | |
374 | replacement=False)) | |
375 | except TypeError: | |
376 | # old distribute API | |
377 | setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools')) | |
378 | ||
379 | if setuptools_dist is None: | |
380 | log.warn('No setuptools distribution found') | |
381 | return | |
382 | # detecting if it was already faked | |
383 | setuptools_location = setuptools_dist.location | |
384 | log.warn('Setuptools installation detected at %s', setuptools_location) | |
385 | ||
386 | # if --root or --preix was provided, and if | |
387 | # setuptools is not located in them, we don't patch it | |
388 | if not _under_prefix(setuptools_location): | |
389 | log.warn('Not patching, --root or --prefix is installing Distribute' | |
390 | ' in another location') | |
391 | return | |
392 | ||
393 | # let's see if its an egg | |
394 | if not setuptools_location.endswith('.egg'): | |
395 | log.warn('Non-egg installation') | |
396 | res = _remove_flat_installation(setuptools_location) | |
397 | if not res: | |
398 | return | |
399 | else: | |
400 | log.warn('Egg installation') | |
401 | pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') | |
402 | if (os.path.exists(pkg_info) and | |
403 | _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): | |
404 | log.warn('Already patched.') | |
405 | return | |
406 | log.warn('Patching...') | |
407 | # let's create a fake egg replacing setuptools one | |
408 | res = _patch_egg_dir(setuptools_location) | |
409 | if not res: | |
410 | return | |
411 | log.warn('Patched done.') | |
412 | _relaunch() | |
413 | ||
414 | ||
415 | def _relaunch(): | |
416 | log.warn('Relaunching...') | |
417 | # we have to relaunch the process | |
418 | args = [sys.executable] + sys.argv | |
419 | sys.exit(subprocess.call(args)) | |
420 | ||
421 | ||
422 | def _extractall(self, path=".", members=None): | |
423 | """Extract all members from the archive to the current working | |
424 | directory and set owner, modification time and permissions on | |
425 | directories afterwards. `path' specifies a different directory | |
426 | to extract to. `members' is optional and must be a subset of the | |
427 | list returned by getmembers(). | |
428 | """ | |
429 | import copy | |
430 | import operator | |
431 | from tarfile import ExtractError | |
432 | directories = [] | |
433 | ||
434 | if members is None: | |
435 | members = self | |
436 | ||
437 | for tarinfo in members: | |
438 | if tarinfo.isdir(): | |
439 | # Extract directories with a safe mode. | |
440 | directories.append(tarinfo) | |
441 | tarinfo = copy.copy(tarinfo) | |
442 | tarinfo.mode = 448 # decimal for oct 0700 | |
443 | self.extract(tarinfo, path) | |
444 | ||
445 | # Reverse sort directories. | |
446 | if sys.version_info < (2, 4): | |
447 | def sorter(dir1, dir2): | |
448 | return cmp(dir1.name, dir2.name) | |
449 | directories.sort(sorter) | |
450 | directories.reverse() | |
451 | else: | |
452 | directories.sort(key=operator.attrgetter('name'), reverse=True) | |
453 | ||
454 | # Set correct owner, mtime and filemode on directories. | |
455 | for tarinfo in directories: | |
456 | dirpath = os.path.join(path, tarinfo.name) | |
457 | try: | |
458 | self.chown(tarinfo, dirpath) | |
459 | self.utime(tarinfo, dirpath) | |
460 | self.chmod(tarinfo, dirpath) | |
461 | except ExtractError: | |
462 | e = sys.exc_info()[1] | |
463 | if self.errorlevel > 1: | |
464 | raise | |
465 | else: | |
466 | self._dbg(1, "tarfile: %s" % e) | |
467 | ||
468 | ||
469 | def main(argv, version=DEFAULT_VERSION): | |
470 | """Install or upgrade setuptools and EasyInstall""" | |
471 | tarball = download_setuptools() | |
472 | _install(tarball) | |
473 | ||
474 | ||
475 | if __name__ == '__main__': | |
476 | main(sys.argv[1:]) |
0 | #!/usr/bin/env bash | |
1 | ||
2 | # A script to remove all files not added to mercurial. | |
3 | ||
4 | hg st | grep "^\? " | sed -e's/^\? //' | xargs rm | |
5 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | '''Mockito is a Test Spy framework.''' | |
21 | ||
22 | ||
23 | from mockito import mock, verify, verifyNoMoreInteractions, verifyZeroInteractions, when, unstub, ArgumentError | |
24 | import inorder | |
25 | from spying import spy | |
26 | from verification import VerificationError | |
27 | ||
28 | # Imports for compatibility | |
29 | from mocking import Mock | |
30 | from matchers import any, contains, times # use package import (``from mockito.matchers import any, contains``) instead of ``from mockito import any, contains`` | |
31 | from verification import never | |
32 | ||
33 | __all__ = ['mock', 'spy', 'verify', 'verifyNoMoreInteractions', 'verifyZeroInteractions', 'inorder', 'when', 'unstub', 'VerificationError', 'ArgumentError', | |
34 | 'Mock', # deprecated | |
35 | 'any', # compatibility | |
36 | 'contains', # compatibility | |
37 | 'never', # compatibility | |
38 | 'times' # deprecated | |
39 | ] |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from mockito import verify as verify_main | |
21 | ||
22 | __author__ = "Serhiy Oplakanets <[email protected]>" | |
23 | ||
24 | ||
25 | def verify(object, *args, **kwargs): | |
26 | kwargs['inorder'] = True | |
27 | return verify_main(object, *args, **kwargs) | |
28 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import matchers | |
21 | ||
22 | ||
23 | class InvocationError(AssertionError): | |
24 | pass | |
25 | ||
26 | class Invocation(object): | |
27 | def __init__(self, mock, method_name): | |
28 | self.method_name = method_name | |
29 | self.mock = mock | |
30 | self.verified = False | |
31 | self.verified_inorder = False | |
32 | self.params = () | |
33 | self.named_params = {} | |
34 | self.answers = [] | |
35 | self.strict = mock.strict | |
36 | ||
37 | def _remember_params(self, params, named_params): | |
38 | self.params = params | |
39 | self.named_params = named_params | |
40 | ||
41 | def __repr__(self): | |
42 | return self.method_name + "(" + ", ".join([repr(p) for p in self.params]) + ")" | |
43 | ||
44 | def answer_first(self): | |
45 | return self.answers[0].answer() | |
46 | ||
47 | class MatchingInvocation(Invocation): | |
48 | @staticmethod | |
49 | def compare(p1, p2): | |
50 | if isinstance(p1, matchers.Matcher): | |
51 | if not p1.matches(p2): return False | |
52 | elif p1 != p2: return False | |
53 | return True | |
54 | ||
55 | def matches(self, invocation): | |
56 | if self.method_name != invocation.method_name: | |
57 | return False | |
58 | if len(self.params) != len(invocation.params): | |
59 | return False | |
60 | if len(self.named_params) != len(invocation.named_params): | |
61 | return False | |
62 | if self.named_params.keys() != invocation.named_params.keys(): | |
63 | return False | |
64 | ||
65 | for x, p1 in enumerate(self.params): | |
66 | if not self.compare(p1, invocation.params[x]): | |
67 | return False | |
68 | ||
69 | for x, p1 in self.named_params.iteritems(): | |
70 | if not self.compare(p1, invocation.named_params[x]): | |
71 | return False | |
72 | ||
73 | return True | |
74 | ||
75 | class RememberedInvocation(Invocation): | |
76 | def __call__(self, *params, **named_params): | |
77 | self._remember_params(params, named_params) | |
78 | self.mock.remember(self) | |
79 | ||
80 | for matching_invocation in self.mock.stubbed_invocations: | |
81 | if matching_invocation.matches(self): | |
82 | return matching_invocation.answer_first() | |
83 | ||
84 | return None | |
85 | ||
86 | class RememberedProxyInvocation(Invocation): | |
87 | '''Remeber params and proxy to method of original object. | |
88 | ||
89 | Calls method on original object and returns it's return value. | |
90 | ''' | |
91 | def __call__(self, *params, **named_params): | |
92 | self._remember_params(params, named_params) | |
93 | self.mock.remember(self) | |
94 | obj = self.mock.original_object | |
95 | try: | |
96 | method = getattr(obj, self.method_name) | |
97 | except AttributeError: | |
98 | raise AttributeError("You tried to call method '%s' which '%s' instance does not have." % (self.method_name, obj.__class__.__name__)) | |
99 | return method(*params, **named_params) | |
100 | ||
101 | class VerifiableInvocation(MatchingInvocation): | |
102 | def __call__(self, *params, **named_params): | |
103 | self._remember_params(params, named_params) | |
104 | matched_invocations = [] | |
105 | for invocation in self.mock.invocations: | |
106 | if self.matches(invocation): | |
107 | matched_invocations.append(invocation) | |
108 | ||
109 | verification = self.mock.pull_verification() | |
110 | verification.verify(self, len(matched_invocations)) | |
111 | ||
112 | for invocation in matched_invocations: | |
113 | invocation.verified = True | |
114 | ||
115 | class StubbedInvocation(MatchingInvocation): | |
116 | def __init__(self, *params): | |
117 | super(StubbedInvocation, self).__init__(*params) | |
118 | if self.mock.strict: | |
119 | self.ensure_mocked_object_has_method(self.method_name) | |
120 | ||
121 | def ensure_mocked_object_has_method(self, method_name): | |
122 | if not self.mock.has_method(method_name): | |
123 | raise InvocationError("You tried to stub a method '%s' the object (%s) doesn't have." | |
124 | % (method_name, self.mock.mocked_obj)) | |
125 | ||
126 | ||
127 | def __call__(self, *params, **named_params): | |
128 | self._remember_params(params, named_params) | |
129 | return AnswerSelector(self) | |
130 | ||
131 | def stub_with(self, answer): | |
132 | self.answers.append(answer) | |
133 | self.mock.stub(self.method_name) | |
134 | self.mock.finish_stubbing(self) | |
135 | ||
136 | class AnswerSelector(object): | |
137 | def __init__(self, invocation): | |
138 | self.invocation = invocation | |
139 | self.answer = None | |
140 | ||
141 | def thenReturn(self, *return_values): | |
142 | for return_value in return_values: | |
143 | self.__then(Return(return_value)) | |
144 | return self | |
145 | ||
146 | def thenRaise(self, *exceptions): | |
147 | for exception in exceptions: | |
148 | self.__then(Raise(exception)) | |
149 | return self | |
150 | ||
151 | def __then(self, answer): | |
152 | if not self.answer: | |
153 | self.answer = CompositeAnswer(answer) | |
154 | self.invocation.stub_with(self.answer) | |
155 | else: | |
156 | self.answer.add(answer) | |
157 | ||
158 | return self | |
159 | ||
160 | class CompositeAnswer(object): | |
161 | def __init__(self, answer): | |
162 | self.answers = [answer] | |
163 | ||
164 | def add(self, answer): | |
165 | self.answers.insert(0, answer) | |
166 | ||
167 | def answer(self): | |
168 | if len(self.answers) > 1: | |
169 | a = self.answers.pop() | |
170 | else: | |
171 | a = self.answers[0] | |
172 | ||
173 | return a.answer() | |
174 | ||
175 | class Raise(object): | |
176 | def __init__(self, exception): | |
177 | self.exception = exception | |
178 | ||
179 | def answer(self): | |
180 | raise self.exception | |
181 | ||
182 | class Return(object): | |
183 | def __init__(self, return_value): | |
184 | self.return_value = return_value | |
185 | ||
186 | def answer(self): | |
187 | return self.return_value |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | '''Matchers for stubbing and verifications. | |
21 | ||
22 | Common matchers for use in stubbing and verifications. | |
23 | ''' | |
24 | ||
25 | __all__ = ['any', 'contains', 'times'] | |
26 | ||
27 | ||
28 | class Matcher: | |
29 | def matches(self, arg): | |
30 | pass | |
31 | ||
32 | class Any(Matcher): | |
33 | def __init__(self, wanted_type=None): | |
34 | self.wanted_type = wanted_type | |
35 | ||
36 | def matches(self, arg): | |
37 | if self.wanted_type: | |
38 | return isinstance(arg, self.wanted_type) | |
39 | else: | |
40 | return True | |
41 | ||
42 | def __repr__(self): | |
43 | return "<Any: %s>" % self.wanted_type | |
44 | ||
45 | class Contains(Matcher): | |
46 | def __init__(self, sub): | |
47 | self.sub = sub | |
48 | ||
49 | def matches(self, arg): | |
50 | if not hasattr(arg, 'find'): | |
51 | return | |
52 | return self.sub and len(self.sub) > 0 and arg.find(self.sub) > -1 | |
53 | ||
54 | def __repr__(self): | |
55 | return "<Contains: '%s'>" % self.sub | |
56 | ||
57 | ||
58 | def any(wanted_type=None): | |
59 | """Matches any() argument OR any(SomeClass) argument | |
60 | Examples: | |
61 | when(mock).foo(any()).thenReturn(1) | |
62 | verify(mock).foo(any(int)) | |
63 | """ | |
64 | return Any(wanted_type) | |
65 | ||
66 | def contains(sub): | |
67 | return Contains(sub) | |
68 | ||
69 | def times(count): | |
70 | return count |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | class MockRegistry: | |
21 | """Registers mock()s, ensures that we only have one mock() per mocked_obj, and | |
22 | iterates over them to unstub each stubbed method. """ | |
23 | ||
24 | def __init__(self): | |
25 | self.mocks = {} | |
26 | ||
27 | def register(self, mock): | |
28 | self.mocks[mock.mocked_obj] = mock | |
29 | ||
30 | def mock_for(self, cls): | |
31 | return self.mocks.get(cls, None) | |
32 | ||
33 | def unstub_all(self): | |
34 | for mock in self.mocks.itervalues(): | |
35 | mock.unstub() | |
36 | self.mocks.clear() | |
37 | ||
38 | mock_registry = MockRegistry()⏎ |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import inspect | |
21 | import invocation | |
22 | from mock_registry import mock_registry | |
23 | import warnings | |
24 | ||
25 | ||
26 | __all__ = ['mock', 'Mock'] | |
27 | ||
28 | class _Dummy(object): pass | |
29 | ||
30 | class TestDouble(object): pass | |
31 | ||
32 | class mock(TestDouble): | |
33 | def __init__(self, mocked_obj=None, strict=True): | |
34 | self.invocations = [] | |
35 | self.stubbed_invocations = [] | |
36 | self.original_methods = [] | |
37 | self.stubbing = None | |
38 | self.verification = None | |
39 | if mocked_obj is None: | |
40 | mocked_obj = _Dummy() | |
41 | strict = False | |
42 | self.mocked_obj = mocked_obj | |
43 | self.strict = strict | |
44 | self.stubbing_real_object = False | |
45 | ||
46 | mock_registry.register(self) | |
47 | ||
48 | def __getattr__(self, method_name): | |
49 | if self.stubbing is not None: | |
50 | return invocation.StubbedInvocation(self, method_name) | |
51 | ||
52 | if self.verification is not None: | |
53 | return invocation.VerifiableInvocation(self, method_name) | |
54 | ||
55 | return invocation.RememberedInvocation(self, method_name) | |
56 | ||
57 | def remember(self, invocation): | |
58 | self.invocations.insert(0, invocation) | |
59 | ||
60 | def finish_stubbing(self, stubbed_invocation): | |
61 | self.stubbed_invocations.insert(0, stubbed_invocation) | |
62 | self.stubbing = None | |
63 | ||
64 | def expect_stubbing(self): | |
65 | self.stubbing = True | |
66 | ||
67 | def pull_verification(self): | |
68 | v = self.verification | |
69 | self.verification = None | |
70 | return v | |
71 | ||
72 | def has_method(self, method_name): | |
73 | return hasattr(self.mocked_obj, method_name) | |
74 | ||
75 | def get_method(self, method_name): | |
76 | return self.mocked_obj.__dict__.get(method_name) | |
77 | ||
78 | def set_method(self, method_name, new_method): | |
79 | setattr(self.mocked_obj, method_name, new_method) | |
80 | ||
81 | def replace_method(self, method_name, original_method): | |
82 | ||
83 | def new_mocked_method(*args, **kwargs): | |
84 | # we throw away the first argument, if it's either self or cls | |
85 | if inspect.isclass(self.mocked_obj) and not isinstance(original_method, staticmethod): | |
86 | args = args[1:] | |
87 | call = self.__getattr__(method_name) # that is: invocation.RememberedInvocation(self, method_name) | |
88 | return call(*args, **kwargs) | |
89 | ||
90 | if isinstance(original_method, staticmethod): | |
91 | new_mocked_method = staticmethod(new_mocked_method) | |
92 | elif isinstance(original_method, classmethod): | |
93 | new_mocked_method = classmethod(new_mocked_method) | |
94 | ||
95 | self.set_method(method_name, new_mocked_method) | |
96 | ||
97 | def stub(self, method_name): | |
98 | original_method = self.get_method(method_name) | |
99 | original = (method_name, original_method) | |
100 | self.original_methods.append(original) | |
101 | ||
102 | # If we're trying to stub real object(not a generated mock), then we should patch object to use our mock method. | |
103 | # TODO: Polymorphism was invented long time ago. Refactor this. | |
104 | if self.stubbing_real_object: | |
105 | self.replace_method(method_name, original_method) | |
106 | ||
107 | def unstub(self): | |
108 | while self.original_methods: | |
109 | method_name, original_method = self.original_methods.pop() | |
110 | self.set_method(method_name, original_method) | |
111 | ||
112 | def Mock(*args, **kwargs): | |
113 | '''A ``mock``() alias. | |
114 | ||
115 | Alias for compatibility. To be removed in version 1.0. | |
116 | ''' | |
117 | warnings.warn("\n`Mock()` is deprecated, please use `mock()` (lower 'm') instead.", DeprecationWarning) | |
118 | return mock(*args, **kwargs) |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import verification | |
21 | from mocking import mock, TestDouble | |
22 | from mock_registry import mock_registry | |
23 | from verification import VerificationError | |
24 | ||
25 | ||
26 | class ArgumentError(Exception): | |
27 | pass | |
28 | ||
29 | def _multiple_arguments_in_use(*args): | |
30 | return len(filter(lambda x: x, args)) > 1 | |
31 | ||
32 | def _invalid_argument(value): | |
33 | return (value is not None and value < 1) or value == 0 | |
34 | ||
35 | def _invalid_between(between): | |
36 | if between is not None: | |
37 | start, end = between | |
38 | if start > end or start < 0: | |
39 | return True | |
40 | return False | |
41 | ||
42 | def verify(obj, times=1, atleast=None, atmost=None, between=None, inorder=False): | |
43 | if times < 0: | |
44 | raise ArgumentError("""'times' argument has invalid value. | |
45 | It should be at least 0. You wanted to set it to: %i""" % times) | |
46 | if _multiple_arguments_in_use(atleast, atmost, between): | |
47 | raise ArgumentError("""Sure you know what you are doing? | |
48 | You can set only one of the arguments: 'atleast', 'atmost' or 'between'.""") | |
49 | if _invalid_argument(atleast): | |
50 | raise ArgumentError("""'atleast' argument has invalid value. | |
51 | It should be at least 1. You wanted to set it to: %i""" % atleast) | |
52 | if _invalid_argument(atmost): | |
53 | raise ArgumentError("""'atmost' argument has invalid value. | |
54 | It should be at least 1. You wanted to set it to: %i""" % atmost) | |
55 | if _invalid_between(between): | |
56 | raise ArgumentError("""'between' argument has invalid value. | |
57 | It should consist of positive values with second number not greater than first | |
58 | e.g. [1, 4] or [0, 3] or [2, 2] | |
59 | You wanted to set it to: %s""" % between) | |
60 | ||
61 | if isinstance(obj, TestDouble): | |
62 | mocked_object = obj | |
63 | else: | |
64 | mocked_object = mock_registry.mock_for(obj) | |
65 | ||
66 | if atleast: | |
67 | mocked_object.verification = verification.AtLeast(atleast) | |
68 | elif atmost: | |
69 | mocked_object.verification = verification.AtMost(atmost) | |
70 | elif between: | |
71 | mocked_object.verification = verification.Between(*between) | |
72 | else: | |
73 | mocked_object.verification = verification.Times(times) | |
74 | ||
75 | if inorder: | |
76 | mocked_object.verification = verification.InOrder(mocked_object.verification) | |
77 | ||
78 | return mocked_object | |
79 | ||
80 | def when(obj, strict=True): | |
81 | if isinstance(obj, mock): | |
82 | theMock = obj | |
83 | else: | |
84 | theMock = mock_registry.mock_for(obj) | |
85 | if theMock is None: | |
86 | theMock = mock(obj, strict=strict) | |
87 | # If we call when on something that is not TestDouble that means we're trying to stub real object, | |
88 | # (class, module etc.). Not to be confused with generating stubs from real classes. | |
89 | theMock.stubbing_real_object = True | |
90 | ||
91 | theMock.expect_stubbing() | |
92 | return theMock | |
93 | ||
94 | def unstub(): | |
95 | """Unstubs all stubbed methods and functions""" | |
96 | mock_registry.unstub_all() | |
97 | ||
98 | def verifyNoMoreInteractions(*mocks): | |
99 | for mock in mocks: | |
100 | for i in mock.invocations: | |
101 | if not i.verified: | |
102 | raise VerificationError("\nUnwanted interaction: " + str(i)) | |
103 | ||
104 | def verifyZeroInteractions(*mocks): | |
105 | verifyNoMoreInteractions(*mocks) |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | '''Spying on real objects.''' | |
21 | ||
22 | from invocation import RememberedProxyInvocation, VerifiableInvocation | |
23 | from mocking import TestDouble | |
24 | ||
25 | __author__ = "Serhiy Oplakanets <[email protected]>" | |
26 | ||
27 | __all__ = ['spy'] | |
28 | ||
29 | def spy(original_object): | |
30 | return Spy(original_object) | |
31 | ||
32 | class Spy(TestDouble): | |
33 | strict = True # spies always have to check if method exists | |
34 | ||
35 | def __init__(self, original_object): | |
36 | self.original_object = original_object | |
37 | self.invocations = [] | |
38 | self.verification = None | |
39 | ||
40 | def __getattr__(self, name): | |
41 | if self.verification: | |
42 | return VerifiableInvocation(self, name) | |
43 | else: | |
44 | return RememberedProxyInvocation(self, name) | |
45 | ||
46 | def remember(self, invocation): | |
47 | self.invocations.insert(0, invocation) | |
48 | ||
49 | def pull_verification(self): | |
50 | v = self.verification | |
51 | self.verification = None | |
52 | return v | |
53 | ⏎ |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | __all__ = ['never', 'VerificationError'] | |
21 | ||
22 | class VerificationError(AssertionError): | |
23 | '''Indicates error during verification of invocations. | |
24 | ||
25 | Raised if verification fails. Error message contains the cause. | |
26 | ''' | |
27 | pass | |
28 | ||
29 | class AtLeast(object): | |
30 | def __init__(self, wanted_count): | |
31 | self.wanted_count = wanted_count | |
32 | ||
33 | def verify(self, invocation, actual_count): | |
34 | if actual_count < self.wanted_count: | |
35 | raise VerificationError("\nWanted at least: %i, actual times: %i" % (self.wanted_count, actual_count)) | |
36 | ||
37 | class AtMost(object): | |
38 | def __init__(self, wanted_count): | |
39 | self.wanted_count = wanted_count | |
40 | ||
41 | def verify(self, invocation, actual_count): | |
42 | if actual_count > self.wanted_count: | |
43 | raise VerificationError("\nWanted at most: %i, actual times: %i" % (self.wanted_count, actual_count)) | |
44 | ||
45 | class Between(object): | |
46 | def __init__(self, wanted_from, wanted_to): | |
47 | self.wanted_from = wanted_from | |
48 | self.wanted_to = wanted_to | |
49 | ||
50 | def verify(self, invocation, actual_count): | |
51 | if actual_count < self.wanted_from or actual_count > self.wanted_to: | |
52 | raise VerificationError("\nWanted between: [%i, %i], actual times: %i" % (self.wanted_from, self.wanted_to, actual_count)) | |
53 | ||
54 | class Times(object): | |
55 | def __init__(self, wanted_count): | |
56 | self.wanted_count = wanted_count | |
57 | ||
58 | def verify(self, invocation, actual_count): | |
59 | if actual_count == self.wanted_count: | |
60 | return | |
61 | if actual_count == 0: | |
62 | raise VerificationError("\nWanted but not invoked: %s" % (invocation)) | |
63 | else: | |
64 | if self.wanted_count == 0: | |
65 | raise VerificationError("\nUnwanted invocation of %s, times: %i" % (invocation, actual_count)) | |
66 | else: | |
67 | raise VerificationError("\nWanted times: %i, actual times: %i" % (self.wanted_count, actual_count)) | |
68 | ||
69 | class InOrder(object): | |
70 | ''' | |
71 | Verifies invocations in order. | |
72 | ||
73 | Verifies if invocation was in expected order, and if yes -- degrades to original Verifier (AtLeast, Times, Between, ...). | |
74 | ''' | |
75 | ||
76 | def __init__(self, original_verification): | |
77 | ''' | |
78 | @param original_verification: Original verifiaction to degrade to if order of invocation was ok. | |
79 | ''' | |
80 | self.original_verification = original_verification | |
81 | ||
82 | def verify(self, wanted_invocation, count): | |
83 | for invocation in reversed(wanted_invocation.mock.invocations): | |
84 | if not invocation.verified_inorder: | |
85 | if not wanted_invocation.matches(invocation): | |
86 | raise VerificationError("\nWanted %s to be invoked, got %s instead" % (wanted_invocation, invocation)) | |
87 | invocation.verified_inorder = True | |
88 | break | |
89 | # proceed with original verification | |
90 | self.original_verification.verify(wanted_invocation, count) | |
91 | ||
92 | never = 0 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import * | |
22 | ||
23 | class Dog: | |
24 | @classmethod | |
25 | def bark(cls): | |
26 | return "woof!" | |
27 | ||
28 | class Cat: | |
29 | @classmethod | |
30 | def meow(cls, m): | |
31 | return cls.__name__ + " " + str(m) | |
32 | ||
33 | class Lion(object): | |
34 | @classmethod | |
35 | def roar(cls): | |
36 | return "Rrrrr!" | |
37 | ||
38 | class ClassMethodsTest(TestBase): | |
39 | ||
40 | def tearDown(self): | |
41 | unstub() | |
42 | ||
43 | def testUnstubs(self): | |
44 | when(Dog).bark().thenReturn("miau!") | |
45 | unstub() | |
46 | self.assertEquals("woof!", Dog.bark()) | |
47 | ||
48 | #TODO decent test case please :) without testing irrelevant implementation details | |
49 | def testUnstubShouldPreserveMethodType(self): | |
50 | when(Dog).bark().thenReturn("miau!") | |
51 | unstub() | |
52 | self.assertTrue(isinstance(Dog.__dict__.get("bark"), classmethod)) | |
53 | ||
54 | def testStubs(self): | |
55 | self.assertEquals("woof!", Dog.bark()) | |
56 | ||
57 | when(Dog).bark().thenReturn("miau!") | |
58 | ||
59 | self.assertEquals("miau!", Dog.bark()) | |
60 | ||
61 | def testStubsClassesDerivedFromTheObjectClass(self): | |
62 | self.assertEquals("Rrrrr!", Lion.roar()) | |
63 | ||
64 | when(Lion).roar().thenReturn("miau!") | |
65 | ||
66 | self.assertEquals("miau!", Lion.roar()) | |
67 | ||
68 | def testVerifiesMultipleCallsOnClassmethod(self): | |
69 | when(Dog).bark().thenReturn("miau!") | |
70 | ||
71 | Dog.bark() | |
72 | Dog.bark() | |
73 | ||
74 | verify(Dog, times(2)).bark() | |
75 | ||
76 | def testFailsVerificationOfMultipleCallsOnClassmethod(self): | |
77 | when(Dog).bark().thenReturn("miau!") | |
78 | ||
79 | Dog.bark() | |
80 | ||
81 | self.assertRaises(VerificationError, verify(Dog, times(2)).bark) | |
82 | ||
83 | def testStubsAndVerifiesClassmethod(self): | |
84 | when(Dog).bark().thenReturn("miau!") | |
85 | ||
86 | self.assertEquals("miau!", Dog.bark()) | |
87 | ||
88 | verify(Dog).bark() | |
89 | ||
90 | def testPreservesClassArgumentAfterUnstub(self): | |
91 | self.assertEquals("Cat foo", Cat.meow("foo")) | |
92 | ||
93 | when(Cat).meow("foo").thenReturn("bar") | |
94 | ||
95 | self.assertEquals("bar", Cat.meow("foo")) | |
96 | ||
97 | unstub() | |
98 | ||
99 | self.assertEquals("Cat foo", Cat.meow("foo")) | |
100 | ||
101 | if __name__ == '__main__': | |
102 | unittest.main() | |
103 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import mockito_util.write_readme | |
21 | ||
22 | #all below code will be merged with README | |
23 | #DELIMINATOR | |
24 | import unittest | |
25 | from mockito import mock, when, verify | |
26 | ||
27 | class DemoTest(unittest.TestCase): | |
28 | def testStubbing(self): | |
29 | # create a mock | |
30 | ourMock = mock() | |
31 | ||
32 | # stub it | |
33 | when(ourMock).getStuff("cool").thenReturn("cool stuff") | |
34 | ||
35 | # use the mock | |
36 | self.assertEqual("cool stuff", ourMock.getStuff("cool")) | |
37 | ||
38 | # what happens when you pass different argument? | |
39 | self.assertEqual(None, ourMock.getStuff("different argument")) | |
40 | ||
41 | def testVerification(self): | |
42 | # create a mock | |
43 | theMock = mock() | |
44 | ||
45 | # use the mock | |
46 | theMock.doStuff("cool") | |
47 | ||
48 | # verify the interactions. Method and parameters must match. Otherwise verification error. | |
49 | verify(theMock).doStuff("cool") | |
50 | ||
51 | #DELIMINATOR | |
52 | #all above code will be merged with README | |
53 | if __name__ == '__main__': | |
54 | unittest.main() | |
55 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import * | |
22 | from mockito.invocation import InvocationError | |
23 | ||
24 | class Dog(object): | |
25 | def waggle(self): | |
26 | return "Wuff!" | |
27 | ||
28 | def bark(self, sound): | |
29 | return "%s!" % sound | |
30 | ||
31 | def do_default_bark(self): | |
32 | return self.bark('Wau') | |
33 | ||
34 | class InstanceMethodsTest(TestBase): | |
35 | def tearDown(self): | |
36 | unstub() | |
37 | ||
38 | def testUnstubAnInstanceMethod(self): | |
39 | original_method = Dog.waggle | |
40 | when(Dog).waggle().thenReturn('Nope!') | |
41 | ||
42 | unstub() | |
43 | ||
44 | rex = Dog() | |
45 | self.assertEquals('Wuff!', rex.waggle()) | |
46 | self.assertEquals(original_method, Dog.waggle) | |
47 | ||
48 | def testStubAnInstanceMethod(self): | |
49 | when(Dog).waggle().thenReturn('Boing!') | |
50 | ||
51 | rex = Dog() | |
52 | self.assertEquals('Boing!', rex.waggle()) | |
53 | ||
54 | def testStubsAnInstanceMethodWithAnArgument(self): | |
55 | when(Dog).bark('Miau').thenReturn('Wuff') | |
56 | ||
57 | rex = Dog() | |
58 | self.assertEquals('Wuff', rex.bark('Miau')) | |
59 | #self.assertEquals('Wuff', rex.bark('Wuff')) | |
60 | ||
61 | def testInvocateAStubbedMethodFromAnotherMethod(self): | |
62 | when(Dog).bark('Wau').thenReturn('Wuff') | |
63 | ||
64 | rex = Dog() | |
65 | self.assertEquals('Wuff', rex.do_default_bark()) | |
66 | verify(Dog).bark('Wau') | |
67 | ||
68 | def testYouCantStubAnUnknownMethodInStrictMode(self): | |
69 | try: | |
70 | when(Dog).barks('Wau').thenReturn('Wuff') | |
71 | self.fail('Stubbing an unknown method should have thrown a exception') | |
72 | except InvocationError: | |
73 | pass | |
74 | ||
75 | def testCallingAStubbedMethodWithUnexpectedArgumentsShouldReturnNone(self): | |
76 | when(Dog).bark('Miau').thenReturn('Wuff') | |
77 | rex = Dog() | |
78 | self.assertEquals(None, rex.bark('Shhh')) | |
79 | ||
80 | ||
81 | def testStubInstancesInsteadOfClasses(self): | |
82 | rex = Dog() | |
83 | when(rex).bark('Miau').thenReturn('Wuff') | |
84 | ||
85 | self.assertEquals('Wuff', rex.bark('Miau')) | |
86 | verify(rex, times=1).bark(any()) | |
87 | ||
88 | max = Dog() | |
89 | self.assertEquals('Miau!', max.bark('Miau')) | |
90 | ||
91 | ||
92 | if __name__ == '__main__': | |
93 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import mock, verify, contains | |
22 | ||
23 | class MatchersTest(TestBase): | |
24 | def testVerifiesUsingContainsMatcher(self): | |
25 | ourMock = mock() | |
26 | ourMock.foo("foobar") | |
27 | ||
28 | verify(ourMock).foo(contains("foo")) | |
29 | verify(ourMock).foo(contains("bar")) | |
30 | ||
31 | class ContainsMatcherTest(TestBase): | |
32 | def testShouldSatisfiySubstringOfGivenString(self): | |
33 | self.assertTrue(contains("foo").matches("foobar")) | |
34 | ||
35 | def testShouldSatisfySameString(self): | |
36 | self.assertTrue(contains("foobar").matches("foobar")) | |
37 | ||
38 | def testShouldNotSatisfiyStringWhichIsNotSubstringOfGivenString(self): | |
39 | self.assertFalse(contains("barfoo").matches("foobar")) | |
40 | ||
41 | def testShouldNotSatisfiyEmptyString(self): | |
42 | self.assertFalse(contains("").matches("foobar")) | |
43 | ||
44 | def testShouldNotSatisfiyNone(self): | |
45 | self.assertFalse(contains(None).matches("foobar")) | |
46 | ||
47 | if __name__ == '__main__': | |
48 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito.invocation import InvocationError | |
22 | from mockito import mock, when | |
23 | ||
24 | class Foo(object): | |
25 | ||
26 | def bar(self): | |
27 | pass | |
28 | ||
29 | class MockingExactTypesTest(TestBase): | |
30 | ||
31 | def testShouldScreamWhenUnknownMethodStubbed(self): | |
32 | ourMock = mock(Foo) | |
33 | ||
34 | when(ourMock).bar().thenReturn("grr"); | |
35 | ||
36 | try: | |
37 | when(ourMock).unknownMethod().thenReturn("grr"); | |
38 | self.fail() | |
39 | except InvocationError: | |
40 | pass | |
41 | ||
42 | def testShouldReturnNoneWhenCallingExistingButUnstubbedMethod(self): | |
43 | ourMock = mock(Foo) | |
44 | self.assertEquals(None, ourMock.bar()) | |
45 | ||
46 | if __name__ == '__main__': | |
47 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import * | |
22 | from mockito.invocation import InvocationError | |
23 | import os | |
24 | ||
25 | class ModuleFunctionsTest(TestBase): | |
26 | def tearDown(self): | |
27 | unstub() | |
28 | ||
29 | def testUnstubs(self): | |
30 | when(os.path).exists("test").thenReturn(True) | |
31 | unstub() | |
32 | self.assertEquals(False, os.path.exists("test")) | |
33 | ||
34 | def testStubs(self): | |
35 | when(os.path).exists("test").thenReturn(True) | |
36 | ||
37 | self.assertEquals(True, os.path.exists("test")) | |
38 | ||
39 | def testStubsConsecutiveCalls(self): | |
40 | when(os.path).exists("test").thenReturn(False).thenReturn(True) | |
41 | ||
42 | self.assertEquals(False, os.path.exists("test")) | |
43 | self.assertEquals(True, os.path.exists("test")) | |
44 | ||
45 | def testStubsMultipleClasses(self): | |
46 | when(os.path).exists("test").thenReturn(True) | |
47 | when(os.path).dirname(any(str)).thenReturn("mocked") | |
48 | ||
49 | self.assertEquals(True, os.path.exists("test")) | |
50 | self.assertEquals("mocked", os.path.dirname("whoah!")) | |
51 | ||
52 | def testVerifiesSuccesfully(self): | |
53 | when(os.path).exists("test").thenReturn(True) | |
54 | ||
55 | os.path.exists("test") | |
56 | ||
57 | verify(os.path).exists("test") | |
58 | ||
59 | def testFailsVerification(self): | |
60 | when(os.path).exists("test").thenReturn(True) | |
61 | ||
62 | self.assertRaises(VerificationError, verify(os.path).exists, "test") | |
63 | ||
64 | def testFailsOnNumberOfCalls(self): | |
65 | when(os.path).exists("test").thenReturn(True) | |
66 | ||
67 | os.path.exists("test") | |
68 | ||
69 | self.assertRaises(VerificationError, verify(os.path, times(2)).exists, "test") | |
70 | ||
71 | def testStubsTwiceAndUnstubs(self): | |
72 | when(os.path).exists("test").thenReturn(False) | |
73 | when(os.path).exists("test").thenReturn(True) | |
74 | ||
75 | self.assertEquals(True, os.path.exists("test")) | |
76 | ||
77 | unstub() | |
78 | ||
79 | self.assertEquals(False, os.path.exists("test")) | |
80 | ||
81 | def testStubsTwiceWithDifferentArguments(self): | |
82 | when(os.path).exists("Foo").thenReturn(False) | |
83 | when(os.path).exists("Bar").thenReturn(True) | |
84 | ||
85 | self.assertEquals(False, os.path.exists("Foo")) | |
86 | self.assertEquals(True, os.path.exists("Bar")) | |
87 | ||
88 | def testShouldThrowIfWeStubAFunctionNotDefinedInTheModule(self): | |
89 | self.assertRaises(InvocationError, lambda:when(os).walk_the_line().thenReturn(None)) | |
90 | ||
91 | ||
92 | if __name__ == '__main__': | |
93 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | #!/usr/bin/env python | |
21 | # coding: utf-8 | |
22 | ||
23 | from mockito_test.test_base import TestBase | |
24 | from mockito import spy, verify, VerificationError | |
25 | ||
26 | class Dummy: | |
27 | def foo(self): | |
28 | return "foo" | |
29 | ||
30 | def bar(self): | |
31 | raise TypeError | |
32 | ||
33 | def return_args(self, *args, **kwargs): | |
34 | return (args, kwargs) | |
35 | ||
36 | class SpyingTest(TestBase): | |
37 | def testPreservesReturnValues(self): | |
38 | dummy = Dummy() | |
39 | spiedDummy = spy(dummy) | |
40 | self.assertEquals(dummy.foo(), spiedDummy.foo()) | |
41 | ||
42 | def testPreservesSideEffects(self): | |
43 | dummy = spy(Dummy()) | |
44 | self.assertRaises(TypeError, dummy.bar) | |
45 | ||
46 | def testPassesArgumentsCorrectly(self): | |
47 | dummy = spy(Dummy()) | |
48 | self.assertEquals((('foo', 1), {'bar': 'baz'}), dummy.return_args('foo', 1, bar='baz')) | |
49 | ||
50 | def testIsVerifiable(self): | |
51 | dummy = spy(Dummy()) | |
52 | dummy.foo() | |
53 | verify(dummy).foo() | |
54 | self.assertRaises(VerificationError, verify(dummy).bar) | |
55 | ||
56 | def testRaisesAttributeErrorIfNoSuchMethod(self): | |
57 | dummy = spy(Dummy()) | |
58 | try: | |
59 | dummy.lol() | |
60 | self.fail("Should fail if no such method.") | |
61 | except AttributeError, e: | |
62 | self.assertEquals("You tried to call method 'lol' which 'Dummy' instance does not have.", str(e)) | |
63 | ⏎ |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import * | |
22 | ||
23 | class Dog: | |
24 | @staticmethod | |
25 | def bark(): | |
26 | return "woof" | |
27 | ||
28 | @staticmethod | |
29 | def barkHardly(*args): | |
30 | return "woof woof" | |
31 | ||
32 | class Cat: | |
33 | @staticmethod | |
34 | def meow(): | |
35 | return "miau" | |
36 | ||
37 | class StaticMethodsTest(TestBase): | |
38 | ||
39 | def tearDown(self): | |
40 | unstub() | |
41 | ||
42 | def testUnstubs(self): | |
43 | when(Dog).bark().thenReturn("miau") | |
44 | unstub() | |
45 | self.assertEquals("woof", Dog.bark()) | |
46 | ||
47 | #TODO decent test case please :) without testing irrelevant implementation details | |
48 | def testUnstubShouldPreserveMethodType(self): | |
49 | when(Dog).bark().thenReturn("miau!") | |
50 | unstub() | |
51 | self.assertTrue(isinstance(Dog.__dict__.get("bark"), staticmethod)) | |
52 | ||
53 | def testStubs(self): | |
54 | self.assertEquals("woof", Dog.bark()) | |
55 | ||
56 | when(Dog).bark().thenReturn("miau") | |
57 | ||
58 | self.assertEquals("miau", Dog.bark()) | |
59 | ||
60 | def testStubsConsecutiveCalls(self): | |
61 | when(Dog).bark().thenReturn(1).thenReturn(2) | |
62 | ||
63 | self.assertEquals(1, Dog.bark()) | |
64 | self.assertEquals(2, Dog.bark()) | |
65 | self.assertEquals(2, Dog.bark()) | |
66 | ||
67 | def testStubsWithArgs(self): | |
68 | self.assertEquals("woof woof", Dog.barkHardly(1, 2)) | |
69 | ||
70 | when(Dog).barkHardly(1, 2).thenReturn("miau") | |
71 | ||
72 | self.assertEquals("miau", Dog.barkHardly(1, 2)) | |
73 | ||
74 | def testStubsButDoesNotMachArguments(self): | |
75 | self.assertEquals("woof woof", Dog.barkHardly(1, "anything")) | |
76 | ||
77 | when(Dog, strict=False).barkHardly(1, 2).thenReturn("miau") | |
78 | ||
79 | self.assertEquals(None, Dog.barkHardly(1)) | |
80 | ||
81 | def testStubsMultipleClasses(self): | |
82 | when(Dog).barkHardly(1, 2).thenReturn(1) | |
83 | when(Dog).bark().thenReturn(2) | |
84 | when(Cat).meow().thenReturn(3) | |
85 | ||
86 | self.assertEquals(1, Dog.barkHardly(1, 2)) | |
87 | self.assertEquals(2, Dog.bark()) | |
88 | self.assertEquals(3, Cat.meow()) | |
89 | ||
90 | unstub() | |
91 | ||
92 | self.assertEquals("woof", Dog.bark()) | |
93 | self.assertEquals("miau", Cat.meow()) | |
94 | ||
95 | def testVerifiesSuccesfully(self): | |
96 | when(Dog).bark().thenReturn("boo") | |
97 | ||
98 | Dog.bark() | |
99 | ||
100 | verify(Dog).bark() | |
101 | ||
102 | def testVerifiesWithArguments(self): | |
103 | when(Dog).barkHardly(1, 2).thenReturn("boo") | |
104 | ||
105 | Dog.barkHardly(1, 2) | |
106 | ||
107 | verify(Dog).barkHardly(1, any()) | |
108 | ||
109 | def testFailsVerification(self): | |
110 | when(Dog).bark().thenReturn("boo") | |
111 | ||
112 | Dog.bark() | |
113 | ||
114 | self.assertRaises(VerificationError, verify(Dog).barkHardly, (1,2)) | |
115 | ||
116 | def testFailsOnInvalidArguments(self): | |
117 | when(Dog).bark().thenReturn("boo") | |
118 | ||
119 | Dog.barkHardly(1, 2) | |
120 | ||
121 | self.assertRaises(VerificationError, verify(Dog).barkHardly, (1,20)) | |
122 | ||
123 | def testFailsOnNumberOfCalls(self): | |
124 | when(Dog).bark().thenReturn("boo") | |
125 | ||
126 | Dog.bark() | |
127 | ||
128 | self.assertRaises(VerificationError, verify(Dog, times(2)).bark) | |
129 | ||
130 | def testStubsAndVerifies(self): | |
131 | when(Dog).bark().thenReturn("boo") | |
132 | ||
133 | self.assertEquals("boo", Dog.bark()) | |
134 | ||
135 | verify(Dog).bark() | |
136 | ||
137 | def testStubsTwiceAndUnstubs(self): | |
138 | when(Dog).bark().thenReturn(1) | |
139 | when(Dog).bark().thenReturn(2) | |
140 | ||
141 | self.assertEquals(2, Dog.bark()) | |
142 | ||
143 | unstub() | |
144 | ||
145 | self.assertEquals("woof", Dog.bark()) | |
146 | ||
147 | def testDoesNotVerifyStubbedCalls(self): | |
148 | when(Dog).bark().thenReturn(1) | |
149 | ||
150 | verify(Dog, times=0).bark() | |
151 | ||
152 | if __name__ == '__main__': | |
153 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import mock, when, verify, times, any | |
22 | ||
23 | class StubbingTest(TestBase): | |
24 | def testStubsWithReturnValue(self): | |
25 | theMock = mock() | |
26 | when(theMock).getStuff().thenReturn("foo") | |
27 | when(theMock).getMoreStuff(1, 2).thenReturn(10) | |
28 | ||
29 | self.assertEquals("foo", theMock.getStuff()) | |
30 | self.assertEquals(10, theMock.getMoreStuff(1, 2)) | |
31 | self.assertEquals(None, theMock.getMoreStuff(1, 3)) | |
32 | ||
33 | def testStubsWhenNoArgsGiven(self): | |
34 | theMock = mock() | |
35 | when(theMock).getStuff().thenReturn("foo") | |
36 | when(theMock).getWidget().thenReturn("bar") | |
37 | ||
38 | self.assertEquals("foo", theMock.getStuff()) | |
39 | self.assertEquals("bar", theMock.getWidget()) | |
40 | ||
41 | def testStubsConsecutivelyWhenNoArgsGiven(self): | |
42 | theMock = mock() | |
43 | when(theMock).getStuff().thenReturn("foo").thenReturn("bar") | |
44 | when(theMock).getWidget().thenReturn("baz").thenReturn("baz2") | |
45 | ||
46 | self.assertEquals("foo", theMock.getStuff()) | |
47 | self.assertEquals("bar", theMock.getStuff()) | |
48 | self.assertEquals("bar", theMock.getStuff()) | |
49 | self.assertEquals("baz", theMock.getWidget()) | |
50 | self.assertEquals("baz2", theMock.getWidget()) | |
51 | self.assertEquals("baz2", theMock.getWidget()) | |
52 | ||
53 | def testStubsWithException(self): | |
54 | theMock = mock() | |
55 | when(theMock).someMethod().thenRaise(Exception("foo")) | |
56 | ||
57 | self.assertRaisesMessage("foo", theMock.someMethod) | |
58 | ||
59 | def testStubsAndVerifies(self): | |
60 | theMock = mock() | |
61 | when(theMock).foo().thenReturn("foo") | |
62 | ||
63 | self.assertEquals("foo", theMock.foo()) | |
64 | verify(theMock).foo() | |
65 | ||
66 | def testStubsVerifiesAndStubsAgain(self): | |
67 | theMock = mock() | |
68 | ||
69 | when(theMock).foo().thenReturn("foo") | |
70 | self.assertEquals("foo", theMock.foo()) | |
71 | verify(theMock).foo() | |
72 | ||
73 | when(theMock).foo().thenReturn("next foo") | |
74 | self.assertEquals("next foo", theMock.foo()) | |
75 | verify(theMock, times(2)).foo() | |
76 | ||
77 | def testOverridesStubbing(self): | |
78 | theMock = mock() | |
79 | ||
80 | when(theMock).foo().thenReturn("foo") | |
81 | when(theMock).foo().thenReturn("bar") | |
82 | ||
83 | self.assertEquals("bar", theMock.foo()) | |
84 | ||
85 | def testStubsAndInvokesTwiceAndVerifies(self): | |
86 | theMock = mock() | |
87 | ||
88 | when(theMock).foo().thenReturn("foo") | |
89 | ||
90 | self.assertEquals("foo", theMock.foo()) | |
91 | self.assertEquals("foo", theMock.foo()) | |
92 | ||
93 | verify(theMock, times(2)).foo() | |
94 | ||
95 | def testStubsAndReturnValuesForMethodWithSameNameAndDifferentArguments(self): | |
96 | theMock = mock() | |
97 | when(theMock).getStuff(1).thenReturn("foo") | |
98 | when(theMock).getStuff(1, 2).thenReturn("bar") | |
99 | ||
100 | self.assertEquals("foo", theMock.getStuff(1)) | |
101 | self.assertEquals("bar", theMock.getStuff(1, 2)) | |
102 | ||
103 | def testStubsAndReturnValuesForMethodWithSameNameAndDifferentNamedArguments(self): | |
104 | repo = mock() | |
105 | when(repo).findby(id=6).thenReturn("John May") | |
106 | when(repo).findby(name="John").thenReturn(["John May", "John Smith"]) | |
107 | ||
108 | self.assertEquals("John May", repo.findby(id=6)) | |
109 | self.assertEquals(["John May", "John Smith"], repo.findby(name="John")) | |
110 | ||
111 | def testStubsForMethodWithSameNameAndNamedArgumentsInArbitraryOrder(self): | |
112 | theMock = mock() | |
113 | ||
114 | when(theMock).foo(first=1, second=2, third=3).thenReturn(True) | |
115 | ||
116 | self.assertEquals(True, theMock.foo(third=3, first=1, second=2)) | |
117 | ||
118 | def testStubsMethodWithSameNameAndMixedArguments(self): | |
119 | repo = mock() | |
120 | when(repo).findby(1).thenReturn("John May") | |
121 | when(repo).findby(1, active_only=True).thenReturn(None) | |
122 | when(repo).findby(name="Sarah").thenReturn(["Sarah Connor"]) | |
123 | when(repo).findby(name="Sarah", active_only=True).thenReturn([]) | |
124 | ||
125 | self.assertEquals("John May", repo.findby(1)) | |
126 | self.assertEquals(None, repo.findby(1, active_only=True)) | |
127 | self.assertEquals(["Sarah Connor"], repo.findby(name="Sarah")) | |
128 | self.assertEquals([], repo.findby(name="Sarah", active_only=True)) | |
129 | ||
130 | def testStubsWithChainedReturnValues(self): | |
131 | theMock = mock() | |
132 | when(theMock).getStuff().thenReturn("foo").thenReturn("bar").thenReturn("foobar") | |
133 | ||
134 | self.assertEquals("foo", theMock.getStuff()) | |
135 | self.assertEquals("bar", theMock.getStuff()) | |
136 | self.assertEquals("foobar", theMock.getStuff()) | |
137 | ||
138 | def testStubsWithChainedReturnValuesAndException(self): | |
139 | theMock = mock() | |
140 | when(theMock).getStuff().thenReturn("foo").thenReturn("bar").thenRaise(Exception("foobar")) | |
141 | ||
142 | self.assertEquals("foo", theMock.getStuff()) | |
143 | self.assertEquals("bar", theMock.getStuff()) | |
144 | self.assertRaisesMessage("foobar", theMock.getStuff) | |
145 | ||
146 | def testStubsWithChainedExceptionAndReturnValue(self): | |
147 | theMock = mock() | |
148 | when(theMock).getStuff().thenRaise(Exception("foo")).thenReturn("bar") | |
149 | ||
150 | self.assertRaisesMessage("foo", theMock.getStuff) | |
151 | self.assertEquals("bar", theMock.getStuff()) | |
152 | ||
153 | def testStubsWithChainedExceptions(self): | |
154 | theMock = mock() | |
155 | when(theMock).getStuff().thenRaise(Exception("foo")).thenRaise(Exception("bar")) | |
156 | ||
157 | self.assertRaisesMessage("foo", theMock.getStuff) | |
158 | self.assertRaisesMessage("bar", theMock.getStuff) | |
159 | ||
160 | def testStubsWithReturnValueBeingException(self): | |
161 | theMock = mock() | |
162 | exception = Exception("foo") | |
163 | when(theMock).getStuff().thenReturn(exception) | |
164 | ||
165 | self.assertEquals(exception, theMock.getStuff()) | |
166 | ||
167 | def testLastStubbingWins(self): | |
168 | theMock = mock() | |
169 | when(theMock).foo().thenReturn(1) | |
170 | when(theMock).foo().thenReturn(2) | |
171 | ||
172 | self.assertEquals(2, theMock.foo()) | |
173 | ||
174 | def testStubbingOverrides(self): | |
175 | theMock = mock() | |
176 | when(theMock).foo().thenReturn(1) | |
177 | when(theMock).foo().thenReturn(2).thenReturn(3) | |
178 | ||
179 | self.assertEquals(2, theMock.foo()) | |
180 | self.assertEquals(3, theMock.foo()) | |
181 | self.assertEquals(3, theMock.foo()) | |
182 | ||
183 | def testStubsWithMatchers(self): | |
184 | theMock = mock() | |
185 | when(theMock).foo(any()).thenReturn(1) | |
186 | ||
187 | self.assertEquals(1, theMock.foo(1)) | |
188 | self.assertEquals(1, theMock.foo(100)) | |
189 | ||
190 | def testStubbingOverrides2(self): | |
191 | theMock = mock() | |
192 | when(theMock).foo(any()).thenReturn(1) | |
193 | when(theMock).foo("oh").thenReturn(2) | |
194 | ||
195 | self.assertEquals(2, theMock.foo("oh")) | |
196 | self.assertEquals(1, theMock.foo("xxx")) | |
197 | ||
198 | def testDoesNotVerifyStubbedCalls(self): | |
199 | theMock = mock() | |
200 | when(theMock).foo().thenReturn(1) | |
201 | ||
202 | verify(theMock, times=0).foo() | |
203 | ||
204 | def testStubsWithMultipleReturnValues(self): | |
205 | theMock = mock() | |
206 | when(theMock).getStuff().thenReturn("foo", "bar", "foobar") | |
207 | ||
208 | self.assertEquals("foo", theMock.getStuff()) | |
209 | self.assertEquals("bar", theMock.getStuff()) | |
210 | self.assertEquals("foobar", theMock.getStuff()) | |
211 | ||
212 | def testStubsWithChainedMultipleReturnValues(self): | |
213 | theMock = mock() | |
214 | when(theMock).getStuff().thenReturn("foo", "bar").thenReturn("foobar") | |
215 | ||
216 | self.assertEquals("foo", theMock.getStuff()) | |
217 | self.assertEquals("bar", theMock.getStuff()) | |
218 | self.assertEquals("foobar", theMock.getStuff()) | |
219 | ||
220 | def testStubsWithMultipleExceptions(self): | |
221 | theMock = mock() | |
222 | when(theMock).getStuff().thenRaise(Exception("foo"), Exception("bar")) | |
223 | ||
224 | self.assertRaisesMessage("foo", theMock.getStuff) | |
225 | self.assertRaisesMessage("bar", theMock.getStuff) | |
226 | ||
227 | def testStubsWithMultipleChainedExceptions(self): | |
228 | theMock = mock() | |
229 | when(theMock).getStuff().thenRaise(Exception("foo"), Exception("bar")).thenRaise(Exception("foobar")) | |
230 | ||
231 | self.assertRaisesMessage("foo", theMock.getStuff) | |
232 | self.assertRaisesMessage("bar", theMock.getStuff) | |
233 | self.assertRaisesMessage("foobar", theMock.getStuff) | |
234 | ||
235 | def testLeavesOriginalMethodUntouchedWhenCreatingStubFromRealClass(self): | |
236 | class Person: | |
237 | def get_name(self): | |
238 | return "original name" | |
239 | ||
240 | # given | |
241 | person = Person() | |
242 | mockPerson = mock(Person) | |
243 | ||
244 | # when | |
245 | when(mockPerson).get_name().thenReturn("stubbed name") | |
246 | ||
247 | # then | |
248 | self.assertEquals("stubbed name", mockPerson.get_name()) | |
249 | self.assertEquals("original name", person.get_name(), 'Original method should not be replaced.') | |
250 | ||
251 | # TODO: verify after stubbing and vice versa | |
252 | ||
253 | if __name__ == '__main__': | |
254 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import unittest | |
21 | ||
22 | class TestBase(unittest.TestCase): | |
23 | ||
24 | def __init__(self, *args, **kwargs): | |
25 | unittest.TestCase.__init__(self, *args, **kwargs) | |
26 | ||
27 | def assertRaisesMessage(self, message, callable, *params): | |
28 | try: | |
29 | if (params): | |
30 | callable(params) | |
31 | else: | |
32 | callable() | |
33 | self.fail('Exception with message "%s" expected, but never raised' % (message)) | |
34 | except Exception, e: | |
35 | # TODO: self.fail() raises AssertionError which is caught here and error message becomes hardly understadable | |
36 | self.assertEquals(message, str(e)) | |
37 | ||
38 | main = unittest.main |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import * | |
21 | from mockito import mock, when, verify, VerificationError, verifyNoMoreInteractions | |
22 | from mockito.verification import never | |
23 | ||
24 | class VerificationErrorsTest(TestBase): | |
25 | ||
26 | def testPrintsNicely(self): | |
27 | theMock = mock() | |
28 | try: | |
29 | verify(theMock).foo() | |
30 | except VerificationError, e: | |
31 | self.assertEquals("\nWanted but not invoked: foo()", str(e)) | |
32 | ||
33 | def testPrintsNicelyOneArgument(self): | |
34 | theMock = mock() | |
35 | try: | |
36 | verify(theMock).foo("bar") | |
37 | except VerificationError, e: | |
38 | self.assertEquals("\nWanted but not invoked: foo('bar')", str(e)) | |
39 | ||
40 | def testPrintsNicelyArguments(self): | |
41 | theMock = mock() | |
42 | try: | |
43 | verify(theMock).foo(1, 2) | |
44 | except VerificationError, e: | |
45 | self.assertEquals("\nWanted but not invoked: foo(1, 2)", str(e)) | |
46 | ||
47 | def testPrintsNicelyStringArguments(self): | |
48 | theMock = mock() | |
49 | try: | |
50 | verify(theMock).foo(1, 'foo') | |
51 | except VerificationError, e: | |
52 | self.assertEquals("\nWanted but not invoked: foo(1, 'foo')", str(e)) | |
53 | ||
54 | def testPrintsOutThatTheActualAndExpectedInvocationCountDiffers(self): | |
55 | theMock = mock() | |
56 | when(theMock).foo().thenReturn(0) | |
57 | ||
58 | theMock.foo() | |
59 | theMock.foo() | |
60 | ||
61 | try: | |
62 | verify(theMock).foo() | |
63 | except VerificationError, e: | |
64 | self.assertEquals("\nWanted times: 1, actual times: 2", str(e)) | |
65 | ||
66 | ||
67 | # TODO: implement | |
68 | def disabled_PrintsNicelyWhenArgumentsDifferent(self): | |
69 | theMock = mock() | |
70 | theMock.foo('foo', 1) | |
71 | try: | |
72 | verify(theMock).foo(1, 'foo') | |
73 | except VerificationError, e: | |
74 | self.assertEquals( | |
75 | """Arguments are different. | |
76 | Wanted: foo(1, 'foo') | |
77 | Actual: foo('foo', 1)""", str(e)) | |
78 | ||
79 | def testPrintsUnwantedInteraction(self): | |
80 | theMock = mock() | |
81 | theMock.foo(1, 'foo') | |
82 | try: | |
83 | verifyNoMoreInteractions(theMock) | |
84 | except VerificationError, e: | |
85 | self.assertEquals("\nUnwanted interaction: foo(1, 'foo')", str(e)) | |
86 | ||
87 | def testPrintsNeverWantedInteractionsNicely(self): | |
88 | theMock = mock() | |
89 | theMock.foo() | |
90 | self.assertRaisesMessage("\nUnwanted invocation of foo(), times: 1", verify(theMock, never).foo) | |
91 | ||
92 | if __name__ == '__main__': | |
93 | unittest.main() |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from test_base import TestBase, main | |
21 | from mockito import mock, verify, inorder, VerificationError , ArgumentError, verifyNoMoreInteractions, verifyZeroInteractions, any | |
22 | from mockito.verification import never | |
23 | ||
24 | class VerificationTestBase(TestBase): | |
25 | def __init__(self, verification_function, *args, **kwargs): | |
26 | self.verification_function = verification_function | |
27 | TestBase.__init__(self, *args, **kwargs) | |
28 | ||
29 | def setUp(self): | |
30 | self.mock = mock() | |
31 | ||
32 | def testVerifies(self): | |
33 | self.mock.foo() | |
34 | self.mock.someOtherMethod(1, "foo", "bar") | |
35 | ||
36 | self.verification_function(self.mock).foo() | |
37 | self.verification_function(self.mock).someOtherMethod(1, "foo", "bar") | |
38 | ||
39 | def testVerifiesWhenMethodIsUsingKeywordArguments(self): | |
40 | self.mock.foo() | |
41 | self.mock.someOtherMethod(1, fooarg="foo", bararg="bar") | |
42 | ||
43 | self.verification_function(self.mock).foo() | |
44 | self.verification_function(self.mock).someOtherMethod(1, bararg="bar", fooarg="foo") | |
45 | ||
46 | def testVerifiesDetectsNamedArguments(self): | |
47 | self.mock.foo(fooarg="foo", bararg="bar") | |
48 | ||
49 | self.verification_function(self.mock).foo(bararg="bar", fooarg="foo") | |
50 | try: | |
51 | self.verification_function(self.mock).foo(bararg="foo", fooarg="bar") | |
52 | self.fail(); | |
53 | except VerificationError: | |
54 | pass | |
55 | ||
56 | def testFailsVerification(self): | |
57 | self.mock.foo("boo") | |
58 | ||
59 | self.assertRaises(VerificationError, self.verification_function(self.mock).foo, "not boo") | |
60 | ||
61 | def testVerifiesAnyTimes(self): | |
62 | self.mock = mock() | |
63 | self.mock.foo() | |
64 | ||
65 | self.verification_function(self.mock).foo() | |
66 | self.verification_function(self.mock).foo() | |
67 | self.verification_function(self.mock).foo() | |
68 | ||
69 | def testVerifiesMultipleCalls(self): | |
70 | self.mock = mock() | |
71 | self.mock.foo() | |
72 | self.mock.foo() | |
73 | self.mock.foo() | |
74 | ||
75 | self.verification_function(self.mock, times=3).foo() | |
76 | ||
77 | def testFailsVerificationOfMultipleCalls(self): | |
78 | self.mock = mock() | |
79 | self.mock.foo() | |
80 | self.mock.foo() | |
81 | self.mock.foo() | |
82 | ||
83 | self.assertRaises(VerificationError, self.verification_function(self.mock, times=2).foo) | |
84 | ||
85 | def testVerifiesUsingAnyMatcher(self): | |
86 | self.mock.foo(1, "bar") | |
87 | ||
88 | self.verification_function(self.mock).foo(1, any()) | |
89 | self.verification_function(self.mock).foo(any(), "bar") | |
90 | self.verification_function(self.mock).foo(any(), any()) | |
91 | ||
92 | def testVerifiesUsingAnyIntMatcher(self): | |
93 | self.mock.foo(1, "bar") | |
94 | ||
95 | self.verification_function(self.mock).foo(any(int), "bar") | |
96 | ||
97 | def testFailsVerificationUsingAnyIntMatcher(self): | |
98 | self.mock.foo(1, "bar") | |
99 | ||
100 | self.assertRaises(VerificationError, self.verification_function(self.mock).foo, 1, any(int)) | |
101 | self.assertRaises(VerificationError, self.verification_function(self.mock).foo, any(int)) | |
102 | ||
103 | def testNumberOfTimesDefinedDirectlyInVerify(self): | |
104 | self.mock.foo("bar") | |
105 | ||
106 | self.verification_function(self.mock, times=1).foo("bar") | |
107 | ||
108 | def testFailsWhenTimesIsLessThanZero(self): | |
109 | self.assertRaises(ArgumentError, self.verification_function, None, -1) | |
110 | ||
111 | def testVerifiesAtLeastTwoWhenMethodInvokedTwice(self): | |
112 | self.mock.foo() | |
113 | self.mock.foo() | |
114 | ||
115 | self.verification_function(self.mock, atleast=2).foo() | |
116 | ||
117 | def testVerifiesAtLeastTwoWhenMethodInvokedFourTimes(self): | |
118 | self.mock.foo() | |
119 | self.mock.foo() | |
120 | self.mock.foo() | |
121 | self.mock.foo() | |
122 | ||
123 | self.verification_function(self.mock, atleast=2).foo() | |
124 | ||
125 | def testFailsWhenMethodInvokedOnceForAtLeastTwoVerification(self): | |
126 | self.mock.foo() | |
127 | self.assertRaises(VerificationError, self.verification_function(self.mock, atleast=2).foo) | |
128 | ||
129 | def testVerifiesAtMostTwoWhenMethodInvokedTwice(self): | |
130 | self.mock.foo() | |
131 | self.mock.foo() | |
132 | ||
133 | self.verification_function(self.mock, atmost=2).foo() | |
134 | ||
135 | def testVerifiesAtMostTwoWhenMethodInvokedOnce(self): | |
136 | self.mock.foo() | |
137 | ||
138 | self.verification_function(self.mock, atmost=2).foo() | |
139 | ||
140 | def testFailsWhenMethodInvokedFourTimesForAtMostTwoVerification(self): | |
141 | self.mock.foo() | |
142 | self.mock.foo() | |
143 | self.mock.foo() | |
144 | self.mock.foo() | |
145 | ||
146 | self.assertRaises(VerificationError, self.verification_function(self.mock, atmost=2).foo) | |
147 | ||
148 | def testVerifiesBetween(self): | |
149 | self.mock.foo() | |
150 | self.mock.foo() | |
151 | ||
152 | self.verification_function(self.mock, between=[1, 2]).foo() | |
153 | self.verification_function(self.mock, between=[2, 3]).foo() | |
154 | self.verification_function(self.mock, between=[1, 5]).foo() | |
155 | self.verification_function(self.mock, between=[2, 2]).foo() | |
156 | ||
157 | def testFailsVerificationWithBetween(self): | |
158 | self.mock.foo() | |
159 | self.mock.foo() | |
160 | self.mock.foo() | |
161 | ||
162 | self.assertRaises(VerificationError, self.verification_function(self.mock, between=[1, 2]).foo) | |
163 | self.assertRaises(VerificationError, self.verification_function(self.mock, between=[4, 9]).foo) | |
164 | ||
165 | def testFailsAtMostAtLeastAndBetweenVerificationWithWrongArguments(self): | |
166 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=0) | |
167 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=-5) | |
168 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=0) | |
169 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=-5) | |
170 | self.assertRaises(ArgumentError, self.verification_function, self.mock, between=[5, 1]) | |
171 | self.assertRaises(ArgumentError, self.verification_function, self.mock, between=[-1, 1]) | |
172 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, atmost=5) | |
173 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, between=[1, 2]) | |
174 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=5, between=[1, 2]) | |
175 | self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, atmost=5, between=[1, 2]) | |
176 | ||
177 | def runTest(self): | |
178 | pass | |
179 | ||
180 | class VerifyTest(VerificationTestBase): | |
181 | def __init__(self, *args, **kwargs): | |
182 | VerificationTestBase.__init__(self, verify, *args, **kwargs) | |
183 | ||
184 | def testVerifyNeverCalled(self): | |
185 | verify(self.mock, never).someMethod() | |
186 | ||
187 | def testVerifyNeverCalledRaisesError(self): | |
188 | self.mock.foo() | |
189 | self.assertRaises(VerificationError, verify(self.mock, never).foo) | |
190 | ||
191 | class InorderVerifyTest(VerificationTestBase): | |
192 | def __init__(self, *args, **kwargs): | |
193 | VerificationTestBase.__init__(self, inorder.verify, *args, **kwargs) | |
194 | ||
195 | def setUp(self): | |
196 | self.mock = mock() | |
197 | ||
198 | def testPassesIfOneIteraction(self): | |
199 | self.mock.first() | |
200 | inorder.verify(self.mock).first() | |
201 | ||
202 | def testPassesIfMultipleInteractions(self): | |
203 | self.mock.first() | |
204 | self.mock.second() | |
205 | self.mock.third() | |
206 | ||
207 | inorder.verify(self.mock).first() | |
208 | inorder.verify(self.mock).second() | |
209 | inorder.verify(self.mock).third() | |
210 | ||
211 | def testFailsIfNoInteractions(self): | |
212 | self.assertRaises(VerificationError, inorder.verify(self.mock).first) | |
213 | ||
214 | def testFailsIfWrongOrderOfInteractions(self): | |
215 | self.mock.first() | |
216 | self.mock.second() | |
217 | ||
218 | self.assertRaises(VerificationError, inorder.verify(self.mock).second) | |
219 | ||
220 | def testErrorMessage(self): | |
221 | self.mock.second() | |
222 | self.mock.first() | |
223 | self.assertRaisesMessage("\nWanted first() to be invoked, got second() instead", inorder.verify(self.mock).first) | |
224 | ||
225 | ||
226 | def testPassesMixedVerifications(self): | |
227 | self.mock.first() | |
228 | self.mock.second() | |
229 | ||
230 | verify(self.mock).first() | |
231 | verify(self.mock).second() | |
232 | ||
233 | inorder.verify(self.mock).first() | |
234 | inorder.verify(self.mock).second() | |
235 | ||
236 | def testFailsMixedVerifications(self): | |
237 | self.mock.second() | |
238 | self.mock.first() | |
239 | ||
240 | # first - normal verifications, they should pass | |
241 | verify(self.mock).first() | |
242 | verify(self.mock).second() | |
243 | ||
244 | # but, inorder verification should fail | |
245 | self.assertRaises(VerificationError, inorder.verify(self.mock).first) | |
246 | ||
247 | ||
248 | class VerifyNoMoreInteractionsTest(TestBase): | |
249 | def testVerifies(self): | |
250 | mockOne, mockTwo = mock(), mock() | |
251 | mockOne.foo() | |
252 | mockTwo.bar() | |
253 | ||
254 | verify(mockOne).foo() | |
255 | verify(mockTwo).bar() | |
256 | verifyNoMoreInteractions(mockOne, mockTwo) | |
257 | ||
258 | def testFails(self): | |
259 | theMock = mock() | |
260 | theMock.foo() | |
261 | self.assertRaises(VerificationError, verifyNoMoreInteractions, theMock) | |
262 | ||
263 | ||
264 | class VerifyZeroInteractionsTest(TestBase): | |
265 | def testVerifies(self): | |
266 | theMock = mock() | |
267 | verifyZeroInteractions(theMock) | |
268 | theMock.foo() | |
269 | self.assertRaises(VerificationError, verifyNoMoreInteractions, theMock) | |
270 | ||
271 | ||
272 | if __name__ == '__main__': | |
273 | main() | |
274 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | from unittest import TestLoader as BaseTestLoader, TestSuite | |
21 | import sys | |
22 | ||
23 | class TestLoader(BaseTestLoader): | |
24 | def loadTestsFromName(self, name, module=None): | |
25 | suite = TestSuite() | |
26 | for test in findTests(name): | |
27 | sys.path.insert(0, name) # python3 compatibility | |
28 | suite.addTests(super(TestLoader, self).loadTestsFromName(test)) | |
29 | del sys.path[0] # python3 compatibility | |
30 | return suite | |
31 | ||
32 | def loadTestsFromNames(self, names, module=None): | |
33 | suite = TestSuite() | |
34 | for name in names: | |
35 | suite.addTests(self.loadTestsFromName(name)) | |
36 | return suite | |
37 | ||
38 | def findTests(dir): | |
39 | import os, re | |
40 | pattern = re.compile('([a-z]+_)+test\.py$') | |
41 | for fileName in os.listdir(dir): | |
42 | if pattern.match(fileName): | |
43 | yield os.path.join(dir, fileName).replace('.py', '').replace(os.sep, '.') | |
44 | ||
45 | __all__ = [TestLoader] | |
46 |
0 | # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste | |
1 | # | |
2 | # Permission is hereby granted, free of charge, to any person obtaining a copy | |
3 | # of this software and associated documentation files (the "Software"), to deal | |
4 | # in the Software without restriction, including without limitation the rights | |
5 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
6 | # copies of the Software, and to permit persons to whom the Software is | |
7 | # furnished to do so, subject to the following conditions: | |
8 | # | |
9 | # The above copyright notice and this permission notice shall be included in | |
10 | # all copies or substantial portions of the Software. | |
11 | # | |
12 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
13 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
14 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
15 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
16 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
17 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
18 | # THE SOFTWARE. | |
19 | ||
20 | import os | |
21 | import re | |
22 | ||
23 | def openFile(f, m='r'): | |
24 | if (os.path.exists(f)): | |
25 | return open(f, m) | |
26 | else: | |
27 | return open('../' + f, m) | |
28 | ||
29 | demo_test = ' '.join(openFile('mockito_test/demo_test.py').readlines()) | |
30 | demo_test = demo_test.split('#DELIMINATOR')[1] | |
31 | ||
32 | readme_before = ''.join(openFile('README.rst').readlines()) | |
33 | token = 'Basic usage:' | |
34 | readme_after = re.compile(token + '.*', re.S).sub(token + '\n' + demo_test, readme_before) | |
35 | ||
36 | if (readme_before != readme_after): | |
37 | readme_file = openFile('README.rst', 'w') | |
38 | readme_file.write(readme_after) | |
39 | print "README updated" | |
40 | else: | |
41 | print "README update not required" |
0 | #!/usr/bin/env python | |
1 | # coding: utf-8 | |
2 | ||
3 | from distribute_setup import use_setuptools | |
4 | use_setuptools() | |
5 | ||
6 | try: | |
7 | from setuptools import setup | |
8 | except ImportError: | |
9 | from distutils.core import setup | |
10 | import sys | |
11 | ||
12 | extra = {} | |
13 | if sys.version_info >= (3,): | |
14 | extra['use_2to3'] = True | |
15 | ||
16 | setup(name='mockito', | |
17 | version='0.5.2', | |
18 | packages=['mockito', 'mockito_test', 'mockito_util'], | |
19 | url='http://code.google.com/p/mockito-python', | |
20 | download_url='http://code.google.com/p/mockito-python/downloads/list', | |
21 | maintainer='Justin Hopper', | |
22 | maintainer_email='[email protected]', | |
23 | license='MIT', | |
24 | description='Spying framework', | |
25 | long_description='Mockito is a spying framework based on Java library with the same name.', | |
26 | classifiers=['Development Status :: 4 - Beta', | |
27 | 'Intended Audience :: Developers', | |
28 | 'License :: OSI Approved :: MIT License', | |
29 | 'Topic :: Software Development :: Testing', | |
30 | 'Programming Language :: Python :: 3' | |
31 | ], | |
32 | test_suite='nose.collector', | |
33 | py_modules=['distribute_setup'], | |
34 | setup_requires=['nose'], | |
35 | **extra) | |
36 |