Codebase list python-mockito / 9983088
Imported Upstream version 0.5.2 Sophie Brun 9 years ago
41 changed file(s) with 2908 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 repo: 0e8bada2d1d2eb28679ee7920c9c95fa05db4ebe
1 node: d3b0a975a8625b665bdf7f6c4d4b1ec27f1e24b2
2 branch: default
3 tag: 0.5.2
0 syntax: glob
1 *.pyc
2 syntax: regexp
3 ^build.*
4 syntax: regexp
5 ^src/build$
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 Szczepan Faber
1 Serhiy Oplakanets
2 Herr Kaste
3 Justin Hopper
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 recursive-include mockito_test *.py
1
2 include AUTHORS
3 include LICENSE
4 include README.rst
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 [nosetests]
1 where=mockito_test
2 detailed-errors=1
0 [nosetests]
1 where=mockito_test
2 detailed-errors=1
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
0 #!/usr/bin/env bash
1
2 # Run unit tests against multiple versions of python.
3
4 VERSIONS=( 2.4 2.5 2.6 2.7 3 )
5
6 for version in ${VERSIONS[@]}; do
7 python${version} setup.py test -q
8 echo "Test results for version ${version}. Press <enter> to continue."
9 read
10 done
11