Codebase list python-mockito / 58bd4f4
Update upstream source from tag 'upstream/1.2.0' Update to upstream version '1.2.0' with Debian dir a3f550a2215ecb4744b4a89bc391242ee0360309 Sophie Brun 4 years ago
78 changed file(s) with 8477 addition(s) and 2742 deletion(s). Raw diff Collapse all Expand all
0 [bumpversion]
1 current_version = 1.2.0
2 commit = True
3 message = Bump version to {new_version}
4 tag = True
5 tag_name = {new_version}
6 parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
7 serialize =
8 {major}.{minor}.{patch}-{release}
9 {major}.{minor}.{patch}
10
11 [bumpversion:file:mockito/__init__.py]
12
13 [bumpversion:part:release]
14 optional_value = release
15 values =
16 dev
17 release
18
0 [flake8]
1 ignore =
2 D,
3 W291,
4 W293,
5 W391,
6 W503,
7 E302,
8 E303,
9 E306,
10 E731
11 exclude = .git,.cache,docs,.env,.build,build
12 max-complexity = 10
13 max-line-length = 79
0 .pc/
0 *.pyc
1 build
2 docs/_build
3 .eggs/
4 .pytest_cache
5 __pycache__
0 language: python
1 python:
2 - '2.7'
3 - '3.4'
4 - '3.5'
5 - '3.6'
6 - '3.7'
7 - '3.8'
8 install:
9 - if [[ $TRAVIS_PYTHON_VERSION == 3.8 ]]; then pip install flake8; fi
10 - pip install .
11 script:
12 - if [[ $TRAVIS_PYTHON_VERSION == 3.8 ]]; then flake8 .; fi
13 - py.test
14 deploy:
15 provider: pypi
16 user: herrkaste
17 password:
18 secure: ou5t21x3ysjuRA4oj0oEJIiwffkrsKMoyBL0AhBc+Qq7bxFIEMCdTgfkh1lrWrhGA0xNIAwDHOL9gJrpYaqeLUx6F0mCQc2zRfNzYNf/t4x0+23WsIGQ1HxWGCW9ixLmtXU+zFGK6pUoLZjPdCT0HjZsAjgKOudTv4M1+BlUhFnmAvdmBKjl3jfNY4h5JWbVrhPg6HzMgfNI+vQ7JIFjHZ4a0i2BqEbTMt/2UZGal+Mau0sEO3/y4Ud0LcTRhtA6VA0J7nEcv85q+/JhqmbXTs9h6Bz1KC3V4nMPaaIpGqhrX20eLI6fxULlB/yuBq5jNXSvDMeH9lRyv5AlDUy9NAh++JciXSYYp3p984V/LEwRKM3VyB+ZUUe+KeLN7rk6d/Q2elFW9IHpw9cSsmbl1zrG4GjP+eCpCOw0lrLO6MAijSCGXEzWN+5ViwMDrGCS/6CjRRUBRxcXBebeo6ZB6Wkw+JWdFLW3s/OMzDeVtOEkuP6qdR7VMNn2uYOkPbiDZO4d5UGS09gGMWYasqxP/QJth2yuF95uQmqOhLuGSzI02YS6+L1/Xh2fEmsD8LFF3ATfA0MZ/phHjjvD/ZUmnVgGczW9p1zEohJ9EDQsV4P2fHzNP6nblcx7iBTzKsEsqcjTpOn7UYhFAsyiga17dhcfa5IU2nSb0JzzIeWdM0Q=
19 on:
20 tags: true
21 python: 3.8
22 branch: master
23 distributions: sdist bdist_wheel
24 repo: kaste/mockito-python
0 MOCKITO CHANGE LOG
1 ==================
2
3 Release 1.2.0 (November 25, 2019)
4 ---------------------------------
5
6 - Code base now is python 3 compatible. No 2to3 anymore.
7 - Fine tune error messages on unexpected calls or verifications. E.g. if you expect ``when(dog).bark('Wuff')`` but on call time do ``dog.bark('Wufff')``. Likewise, if you call ``dog.bark('Miau')`` and then ``verify(dog).bark('Maui')``.
8 - @felixonmars fixed a small compatibility issue with python 3.8
9 - Mocking properties has become a bit easier. (#26) E.g.
10
11 prop = mock()
12 when(m).__get__(...).thenReturn(23)
13 m = mock({'name': prop})
14
15
16 Release 1.1.1 (August 28, 2018)
17 -------------------------------
18
19 - Fix: The context manager (``with``) has now a proper implementation
20 - Fix: Calling ``patch`` with two arguments can now be used with ``with``
21 - Fix: Do not treat the placeholder arguments (Ellipsis, args, kwargs) as special on call time anymore. (T.i. they only have a meaning when stubbing or verifying.)
22 - Enhancement: Changed some truthy or equality tests to identity (``is``) tests. This reduces edge-cases where some user object defines ``__eq__`` or ``__bool__``. (Hello _numpy_!)
23
24
25 Release 1.1.0 (May 2, 2018)
26 ---------------------------
27
28 - Added ``forget_invocations`` function. Thanks to @maximkulkin
29
30 This is generally useful if you already call mocks during your setup routine.
31 Now you could call ``forget_invocations`` at the end of your setup, and
32 have a clean 'recording' for your actual test code. T.i. you don't have
33 to count the invocations from your setup code anymore.
34
35
36 Release 1.0.12 (June 3, 2017)
37 -----------------------------
38
39 - Better error messages for failed verifications. By @lwoydziak
40
41
42 Release 1.0.7 - 1.0.10 (January 31 - February 2, 2017)
43 ------------------------------------------------------
44
45 - ``verifyZeroInteractions`` implemented. This is actually a *breaking change*, because ``verifyZeroInteractions`` was an alias for ``verifyNoMoreInteractions`` (sic!). If you used it, just call the other function.
46
47 - ``verifyStubbedInvocationsAreUsed`` implemented. This is meant to be called right before an ``unstub`` and should improve long time maintenance. It doesn't help during design time. Note that `pytest-mockito` automatically calls this for you.
48
49 - All `verify*` functions now warn you if you pass in an object which was never stubbed.
50
51
52 Release 1.0.0 - 1.0.5 (January 24 - 27, 2017)
53 ---------------------------------------------
54
55 This is a major update; mostly because of internal code reorganization (`imports`) it cannot be guaranteed that this will not break for you. Though if you just used the public API you should be fine. None of the vintage old tests have been removed and they at least pass.
56
57 In general unclassified imports (``from mocktio import *``) are not recommended. But if you did, we do not export `Mock` anymore. `Mock` has been deprecated long ago and is now for internal use only. You must use `mock`.
58
59 Another important change is, that *mockito*'s strict mode is far more strict than before. We now generally try to match the signature of the target method
60 with your usage. Usually this should help you find bugs in your code, because
61 it will make it easier to spot changing interfaces.
62
63 - ``mock``, ``when``, ``verify`` return mostly empty objects. It is unlikely to have a method_name clash.
64
65 - Specced mocks ``instance = mock(Class)`` will pass isinstance tests like ``isinstance(instance, Class)``
66
67 - For ``when`` and ``verify`` the function signature or argument matchers can be greatly simplified. E.g. ``when(requests).get(...).thenReturn('OK')`` will match any argument you pass in. There are ``args`` and ``kwargs`` matchers as well. So ``when(requests).get('https://...', **kwargs).thenReturn(...)`` will make an exact match on the first argument, the url, and ignore all the headers and other stuff.
68
69 - Mocks can be preconfigured: ``mock({'text': 'OK'})``. For specced mocks this would be e.g. ``mock({'text': 'OK'}, spec=requests.Response)``.
70
71 - If you mock or patch an object, the function signatures will be matched. So::
72
73 def foo(a, b=1): ...
74
75 when(main).foo(12) # will pass
76 when(main).foo(c=13) # will raise immediately
77
78 - Mock Dummies are now callable::
79
80 m = mock()
81 m(1, 2)
82 verify(m).__call__(...)
83
84 - ``Mock()`` is now an implementation detail; it is **not** exported anymore. Use ``mock()``.
85
86 - You can unstub individual patched objects ``unstub(obj)``. (Before it was all or nothing.)
87
88 - Added basic context manager support when using ``when``. Note that ``verify`` has to be called within the with context.
89
90 ::
91
92 with when(rex).waggle().thenReturn('Yup'):
93 assert rex.waggle() == 'Yup'
94 verify(rex).waggle()
95
96 - Aliased ``any_`` to ``ANY``, ``args`` to ``ARGS`` and ``kwargs`` to ``KWARGS``. You can use python's builtin ``any`` as a stand in for ``ANY``.
97
98 - As a convenience you can use our ``any_`` matcher like a type instead of ``any_()``::
99
100 dummy(1)
101 verify(dummy).__call__(ANY)
102
103 - Added ``when2``, ``expect``, ``spy2``
104
105 - Make the mocked function (replacement) more inspectable. Copy `__doc__`, `__name__` etc.
106
107 - You can configure magic methods on mocks::
108
109 dummy = mock()
110 when(dummy).__getitem__(1).thenReturn(2)
111 assert dummy[1] == 2
112
113
114
115 Release 0.7.1 (December 27, 2016)
116 ---------------------------------
117
118 - Fix: Allow ``verifyNoMoreInteractions`` call for real (stubbed) objects
119
120
121 Release 0.7.0 (July 15, 2016)
122 -----------------------------
123
124 - Added a ton of new argument matchers. Namely::
125
126 'and_', 'or_', 'not_', 'eq', 'neq', 'lt', 'lte', 'gt', 'gte',
127 'arg_that', 'matches', 'captor'
128
129 - Aliases ``any`` matcher to ``any_`` because it's a builtin.
130 - Fixes an issue where mockito could not correctly verify your function invocations, if you grabbed a method from its object and used it ('detached') as a plain function::
131
132 m = mock()
133 f = m.foo # detach
134 f(1, 2) # pass it around and use it like a function
135 f(2, 3)
136 verify(m).foo(...) # finally verify interactions
137
138 Thank you @maximkulkin
139
140
141 Release 0.6.1 (May 20, 2016)
142 ----------------------------
143
144 - Added ``thenAnswer(callable)``. The callable will be called to compute the answer the stubbed method will return. For that it will receive the arguments of the caller::
145
146 m = mock()
147 when(m).do_times(any(), any()).thenAnswer(lambda one, two: one * two)
148 self.assertEquals(20, m.do_times(5, 4))
149
150 Thank you @stubbsd
151
152 Release 0.6.0 (April 25, 2016)
153 ------------------------------
154
155 - Print keyword arguments nicely.
156 - Be very forgiving about return values and assume None as default. T.i. ``when(Dog).bark('Miau').thenReturn()`` is enough to return None.
157 - Make keyword argument order unimportant.
158 - BREAKING CHANGE: Throw early when calling not expected methods in strict mode.
159
160 Release 0.5.3 (April 23, 2016)
161 ------------------------------
162
163 - Remove hard coded distribute setup files.
164
165 Release 0.5.1 (August 4, 2010)
166 ------------------------------
167 BUG Fixes:
168 - Fixed issue #9 [http://bitbucket.org/szczepiq/mockito-python/issue/9] : Generating stubs from classes caused method to be replaced in original classes.
169
170 Release 0.5.0 (July 26, 2010)
171 -----------------------------
172 API Changes:
173 - Added possibility to spy on real objects.
174 - Added "never" syntactic sugar for verifications.
175
176 BUG Fixes:
177 - Fixed issue with named arguments matching.
178
179 Other Changes:
180 - Python 2.7 support
181 - Deprecated APIs now generate deprecation warnings.
182
183 Release 0.4.0 (July 2, 2010)
184 ----------------------------
185 API Changes:
186 - Added possibility to verify invocations in order.
187
188 BUG Fixes:
189 - Fixed issue with installing mockito from egg without distribute installed.
190
191 Release 0.3.1
192 -------------
193 Bug-fix release.
194
195 Bug Fixes:
196 - Fixed annoying issue #8 [http://bitbucket.org/szczepiq/mockito-python/issue/8]
197
198 Release 0.3.0
199 -------------
200 API Changes:
201 - Renamed mock creation method from "Mock" (upper "M") to "mock". Old name stays for compatibility until 1.0 release.
202 Other Changes:
203 - Official Python3 support via distutils + 2to3.
204
0 Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 Copyright (c) 2008-2019 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11
22 Permission is hereby granted, free of charge, to any person obtaining a copy
33 of this software and associated documentation files (the "Software"), to deal
1515 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1616 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1717 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18 THE SOFTWARE.
18 THE SOFTWARE.
0 recursive-include mockito_test *.py
1
20 include AUTHORS
1 include CHANGES.txt
32 include LICENSE
43 include README.rst
4
5 global-exclude *.py[co]
+0
-16
PKG-INFO less more
0 Metadata-Version: 1.0
1 Name: mockito
2 Version: 0.5.2
3 Summary: Spying framework
4 Home-page: http://code.google.com/p/mockito-python
5 Author: Justin Hopper
6 Author-email: [email protected]
7 License: MIT
8 Download-URL: http://code.google.com/p/mockito-python/downloads/list
9 Description: Mockito is a spying framework based on Java library with the same name.
10 Platform: UNKNOWN
11 Classifier: Development Status :: 4 - Beta
12 Classifier: Intended Audience :: Developers
13 Classifier: License :: OSI Approved :: MIT License
14 Classifier: Topic :: Software Development :: Testing
15 Classifier: Programming Language :: Python :: 3
0 Mockito is a spying framework based on Java library with the same name.
0 Mockito is a spying framework originally based on `the Java library with the same name
1 <https://github.com/mockito/mockito>`_.
12
2 1. To install:
3 .. image:: https://travis-ci.org/kaste/mockito-python.svg?branch=master
4 :target: https://travis-ci.org/kaste/mockito-python
35
4 $ python setup.py install
56
6 2. To run all tests:
7 Install
8 =======
79
8 $ python setup.py test
10 ``pip install mockito``
911
10 3. For more info, see:
1112
12 __ http://code.google.com/p/mockito-python/
13
14 Feel free to contribute more documentation or feedback!
1513
16 4. Our user and developer discussion group is:
14 Quick Start
15 ===========
1716
18 __ http://groups.google.com/group/mockito-python
17 90% use case is that you want to stub out a side effect.
1918
20 5. Mockito is licensed under the MIT license
19 ::
2120
22 6. Library was tested with the following Python versions:
21 from mockito import when, mock, unstub
2322
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:
23 when(os.path).exists('/foo').thenReturn(True)
3124
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
25 # or:
26 import requests # the famous library
27 # you actually want to return a Response-like obj, we'll fake it
28 response = mock({'status_code': 200, 'text': 'Ok'})
29 when(requests).get(...).thenReturn(response)
30
31 # use it
32 requests.get('http://google.com/')
33
34 # clean up
35 unstub()
36
37
38
39
40 Read the docs
41 =============
42
43 http://mockito-python.readthedocs.io/en/latest/
44
45
46 Run the tests
47 -------------
48
49 ::
50
51 pip install pytest
52 py.test
0 bumpversion release --tag
1 bumpversion patch --no-tag --message "master is {new_version}"
+0
-477
distribute_setup.py less more
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 # Makefile for Sphinx documentation
1 #
2
3 # You can set these variables from the command line.
4 SPHINXOPTS =
5 SPHINXBUILD = sphinx-build
6 PAPER =
7 BUILDDIR = _build
8
9 # User-friendly check for sphinx-build
10 ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
11 $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/)
12 endif
13
14 # Internal variables.
15 PAPEROPT_a4 = -D latex_paper_size=a4
16 PAPEROPT_letter = -D latex_paper_size=letter
17 ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
18 # the i18n builder cannot share the environment and doctrees with the others
19 I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
20
21 .PHONY: help
22 help:
23 @echo "Please use \`make <target>' where <target> is one of"
24 @echo " html to make standalone HTML files"
25 @echo " dirhtml to make HTML files named index.html in directories"
26 @echo " singlehtml to make a single large HTML file"
27 @echo " pickle to make pickle files"
28 @echo " json to make JSON files"
29 @echo " htmlhelp to make HTML files and a HTML help project"
30 @echo " qthelp to make HTML files and a qthelp project"
31 @echo " applehelp to make an Apple Help Book"
32 @echo " devhelp to make HTML files and a Devhelp project"
33 @echo " epub to make an epub"
34 @echo " epub3 to make an epub3"
35 @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
36 @echo " latexpdf to make LaTeX files and run them through pdflatex"
37 @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
38 @echo " text to make text files"
39 @echo " man to make manual pages"
40 @echo " texinfo to make Texinfo files"
41 @echo " info to make Texinfo files and run them through makeinfo"
42 @echo " gettext to make PO message catalogs"
43 @echo " changes to make an overview of all changed/added/deprecated items"
44 @echo " xml to make Docutils-native XML files"
45 @echo " pseudoxml to make pseudoxml-XML files for display purposes"
46 @echo " linkcheck to check all external links for integrity"
47 @echo " doctest to run all doctests embedded in the documentation (if enabled)"
48 @echo " coverage to run coverage check of the documentation (if enabled)"
49 @echo " dummy to check syntax errors of document sources"
50
51 .PHONY: clean
52 clean:
53 rm -rf $(BUILDDIR)/*
54
55 .PHONY: html
56 html:
57 $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
58 @echo
59 @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
60
61 .PHONY: dirhtml
62 dirhtml:
63 $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
64 @echo
65 @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
66
67 .PHONY: singlehtml
68 singlehtml:
69 $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
70 @echo
71 @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
72
73 .PHONY: pickle
74 pickle:
75 $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
76 @echo
77 @echo "Build finished; now you can process the pickle files."
78
79 .PHONY: json
80 json:
81 $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
82 @echo
83 @echo "Build finished; now you can process the JSON files."
84
85 .PHONY: htmlhelp
86 htmlhelp:
87 $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
88 @echo
89 @echo "Build finished; now you can run HTML Help Workshop with the" \
90 ".hhp project file in $(BUILDDIR)/htmlhelp."
91
92 .PHONY: qthelp
93 qthelp:
94 $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
95 @echo
96 @echo "Build finished; now you can run "qcollectiongenerator" with the" \
97 ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
98 @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mockito-python.qhcp"
99 @echo "To view the help file:"
100 @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mockito-python.qhc"
101
102 .PHONY: applehelp
103 applehelp:
104 $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
105 @echo
106 @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
107 @echo "N.B. You won't be able to view it unless you put it in" \
108 "~/Library/Documentation/Help or install it in your application" \
109 "bundle."
110
111 .PHONY: devhelp
112 devhelp:
113 $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
114 @echo
115 @echo "Build finished."
116 @echo "To view the help file:"
117 @echo "# mkdir -p $$HOME/.local/share/devhelp/mockito-python"
118 @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mockito-python"
119 @echo "# devhelp"
120
121 .PHONY: epub
122 epub:
123 $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
124 @echo
125 @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
126
127 .PHONY: epub3
128 epub3:
129 $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
130 @echo
131 @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
132
133 .PHONY: latex
134 latex:
135 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
136 @echo
137 @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
138 @echo "Run \`make' in that directory to run these through (pdf)latex" \
139 "(use \`make latexpdf' here to do that automatically)."
140
141 .PHONY: latexpdf
142 latexpdf:
143 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
144 @echo "Running LaTeX files through pdflatex..."
145 $(MAKE) -C $(BUILDDIR)/latex all-pdf
146 @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
147
148 .PHONY: latexpdfja
149 latexpdfja:
150 $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
151 @echo "Running LaTeX files through platex and dvipdfmx..."
152 $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
153 @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
154
155 .PHONY: text
156 text:
157 $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
158 @echo
159 @echo "Build finished. The text files are in $(BUILDDIR)/text."
160
161 .PHONY: man
162 man:
163 $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
164 @echo
165 @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
166
167 .PHONY: texinfo
168 texinfo:
169 $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
170 @echo
171 @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
172 @echo "Run \`make' in that directory to run these through makeinfo" \
173 "(use \`make info' here to do that automatically)."
174
175 .PHONY: info
176 info:
177 $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
178 @echo "Running Texinfo files through makeinfo..."
179 make -C $(BUILDDIR)/texinfo info
180 @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
181
182 .PHONY: gettext
183 gettext:
184 $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
185 @echo
186 @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
187
188 .PHONY: changes
189 changes:
190 $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
191 @echo
192 @echo "The overview file is in $(BUILDDIR)/changes."
193
194 .PHONY: linkcheck
195 linkcheck:
196 $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
197 @echo
198 @echo "Link check complete; look for any errors in the above output " \
199 "or in $(BUILDDIR)/linkcheck/output.txt."
200
201 .PHONY: doctest
202 doctest:
203 $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
204 @echo "Testing of doctests in the sources finished, look at the " \
205 "results in $(BUILDDIR)/doctest/output.txt."
206
207 .PHONY: coverage
208 coverage:
209 $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
210 @echo "Testing of coverage in the sources finished, look at the " \
211 "results in $(BUILDDIR)/coverage/python.txt."
212
213 .PHONY: xml
214 xml:
215 $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
216 @echo
217 @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
218
219 .PHONY: pseudoxml
220 pseudoxml:
221 $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
222 @echo
223 @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
224
225 .PHONY: dummy
226 dummy:
227 $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
228 @echo
229 @echo "Build finished. Dummy builder generates no files."
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 @import url("basic.css");
53
54 /* -- page layout ----------------------------------------------------------- */
55
56 body {
57 font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif;
58 font-size: 17px;
59 background-color: #fff;
60 color: #000;
61 margin: 0;
62 padding: 0;
63 }
64
65
66 div.document {
67 width: 940px;
68 margin: 30px auto 0 auto;
69 }
70
71 div.documentwrapper {
72 float: left;
73 width: 100%;
74 }
75
76 div.bodywrapper {
77 margin: 0 0 0 220px;
78 }
79
80 div.sphinxsidebar {
81 width: 220px;
82 font-size: 14px;
83 line-height: 1.5;
84 }
85
86 hr {
87 border: 1px solid #B1B4B6;
88 }
89
90 div.body {
91 background-color: #fff;
92 color: #3E4349;
93 padding: 0 30px 0 30px;
94 }
95
96 div.body > .section {
97 text-align: left;
98 }
99
100 div.footer {
101 width: 940px;
102 margin: 20px auto 30px auto;
103 font-size: 14px;
104 color: #888;
105 text-align: right;
106 }
107
108 div.footer a {
109 color: #888;
110 }
111
112 p.caption {
113 font-family: inherit;
114 font-size: inherit;
115 }
116
117
118 div.relations {
119 display: none;
120 }
121
122
123 div.sphinxsidebar a {
124 color: #444;
125 text-decoration: none;
126 border-bottom: 1px dotted #999;
127 }
128
129 div.sphinxsidebar a:hover {
130 border-bottom: 1px solid #999;
131 }
132
133 div.sphinxsidebarwrapper {
134 padding: 18px 10px;
135 }
136
137 div.sphinxsidebarwrapper p.logo {
138 padding: 0;
139 margin: -10px 0 0 0px;
140 text-align: center;
141 }
142
143 div.sphinxsidebarwrapper h1.logo {
144 margin-top: -10px;
145 text-align: center;
146 margin-bottom: 5px;
147 text-align: left;
148 }
149
150 div.sphinxsidebarwrapper h1.logo-name {
151 margin-top: 0px;
152 }
153
154 div.sphinxsidebarwrapper p.blurb {
155 margin-top: 0;
156 font-style: normal;
157 }
158
159 div.sphinxsidebar h3,
160 div.sphinxsidebar h4 {
161 font-family: 'Garamond', 'Georgia', serif;
162 color: #444;
163 font-size: 24px;
164 font-weight: normal;
165 margin: 0 0 5px 0;
166 padding: 0;
167 }
168
169 div.sphinxsidebar h4 {
170 font-size: 20px;
171 }
172
173 div.sphinxsidebar h3 a {
174 color: #444;
175 }
176
177 div.sphinxsidebar p.logo a,
178 div.sphinxsidebar h3 a,
179 div.sphinxsidebar p.logo a:hover,
180 div.sphinxsidebar h3 a:hover {
181 border: none;
182 }
183
184 div.sphinxsidebar p {
185 color: #555;
186 margin: 10px 0;
187 }
188
189 div.sphinxsidebar ul {
190 margin: 10px 0;
191 padding: 0;
192 color: #000;
193 }
194
195 div.sphinxsidebar ul li.toctree-l1 > a {
196 font-size: 120%;
197 }
198
199 div.sphinxsidebar ul li.toctree-l2 > a {
200 font-size: 110%;
201 }
202
203 div.sphinxsidebar input {
204 border: 1px solid #CCC;
205 font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif;
206 font-size: 1em;
207 }
208
209 div.sphinxsidebar hr {
210 border: none;
211 height: 1px;
212 color: #AAA;
213 background: #AAA;
214
215 text-align: left;
216 margin-left: 0;
217 width: 50%;
218 }
219
220 /* -- body styles ----------------------------------------------------------- */
221
222 a {
223 color: #004B6B;
224 text-decoration: underline;
225 }
226
227 a:hover {
228 color: #6D4100;
229 text-decoration: underline;
230 }
231
232 div.body h1,
233 div.body h2,
234 div.body h3,
235 div.body h4,
236 div.body h5,
237 div.body h6 {
238 font-family: 'Garamond', 'Georgia', serif;
239 font-weight: normal;
240 margin: 30px 0px 10px 0px;
241 padding: 0;
242 }
243
244 div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }
245 div.body h2 { font-size: 180%; }
246 div.body h3 { font-size: 150%; }
247 div.body h4 { font-size: 130%; }
248 div.body h5 { font-size: 100%; }
249 div.body h6 { font-size: 100%; }
250
251 a.headerlink {
252 color: #DDD;
253 padding: 0 4px;
254 text-decoration: none;
255 }
256
257 a.headerlink:hover {
258 color: #444;
259 background: #EAEAEA;
260 }
261
262 div.body p, div.body dd, div.body li {
263 line-height: 1.4em;
264 }
265
266 div.admonition {
267 margin: 20px 0px;
268 padding: 10px 30px;
269 background-color: #EEE;
270 border: 1px solid #CCC;
271 }
272
273 div.admonition tt.xref, div.admonition code.xref, div.admonition a tt {
274 background-color: ;
275 border-bottom: 1px solid #fafafa;
276 }
277
278 dd div.admonition {
279 /* margin-left: -60px;
280 padding-left: 60px;
281 */}
282
283 div.admonition p.admonition-title {
284 font-family: 'Garamond', 'Georgia', serif;
285 font-weight: normal;
286 font-size: 18px;
287 margin: 0 0 10px 0;
288 padding: 0;
289 /*line-height: 1;*/
290 }
291
292 div.admonition p.last {
293 margin-bottom: 0;
294 }
295
296 div.highlight {
297 background-color: #fff;
298 }
299
300 dt:target, .highlight {
301 background: #FAF3E8;
302 }
303
304 div.warning {
305 background-color: #FCC;
306 border: 1px solid #FAA;
307 }
308
309 div.danger {
310 background-color: #FCC;
311 border: 1px solid #FAA;
312 -moz-box-shadow: 2px 2px 4px #D52C2C;
313 -webkit-box-shadow: 2px 2px 4px #D52C2C;
314 box-shadow: 2px 2px 4px #D52C2C;
315 }
316
317 div.error {
318 background-color: #FCC;
319 border: 1px solid #FAA;
320 -moz-box-shadow: 2px 2px 4px #D52C2C;
321 -webkit-box-shadow: 2px 2px 4px #D52C2C;
322 box-shadow: 2px 2px 4px #D52C2C;
323 }
324
325 div.caution {
326 background-color: #FCC;
327 border: 1px solid #FAA;
328 }
329
330 div.attention {
331 background-color: #FCC;
332 border: 1px solid #FAA;
333 }
334
335 div.important {
336 background-color: #EEE;
337 border: 1px solid #CCC;
338 }
339
340 div.note {
341 background-color: #EEE;
342 border: 1px solid #CCC;
343 }
344
345 div.tip {
346 background-color: #EEE;
347 border: 1px solid #CCC;
348 }
349
350 div.hint {
351 background-color: #EEE;
352 border: 1px solid #CCC;
353 }
354
355 div.seealso {
356 background-color: #EEE;
357 border: 1px solid #CCC;
358 }
359
360 div.topic {
361 background-color: #EEE;
362 }
363
364 p.admonition-title {
365 display: inline;
366 }
367
368 p.admonition-title:after {
369 content: ":";
370 }
371
372 pre, tt, code {
373 font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
374 font-size: 0.9em;
375 }
376
377 .hll {
378 background-color: #FFC;
379 margin: 0 -12px;
380 padding: 0 12px;
381 display: block;
382 }
383
384 img.screenshot {
385 }
386
387 tt.descname, tt.descclassname, code.descname, code.descclassname {
388 font-size: 0.95em;
389 }
390
391 tt.descname, code.descname {
392 padding-right: 0.08em;
393 }
394
395 img.screenshot {
396 -moz-box-shadow: 2px 2px 4px #EEE;
397 -webkit-box-shadow: 2px 2px 4px #EEE;
398 box-shadow: 2px 2px 4px #EEE;
399 }
400
401 table.docutils {
402 border: 1px solid #888;
403 -moz-box-shadow: 2px 2px 4px #EEE;
404 -webkit-box-shadow: 2px 2px 4px #EEE;
405 box-shadow: 2px 2px 4px #EEE;
406 }
407
408 table.docutils td, table.docutils th {
409 border: 1px solid #888;
410 padding: 0.25em 0.7em;
411 }
412
413 table.field-list, table.footnote {
414 border: none;
415 -moz-box-shadow: none;
416 -webkit-box-shadow: none;
417 box-shadow: none;
418 }
419
420 table.footnote {
421 margin: 15px 0;
422 width: 100%;
423 border: 1px solid #EEE;
424 background: #FDFDFD;
425 font-size: 0.9em;
426 }
427
428 table.footnote + table.footnote {
429 margin-top: -15px;
430 border-top: none;
431 }
432
433 table.field-list th {
434 padding: 0 0.8em 0 0;
435 }
436
437 table.field-list td {
438 padding: 0;
439 }
440
441 table.field-list p {
442 margin-bottom: 0.8em;
443 }
444
445 table.footnote td.label {
446 width: .1px;
447 padding: 0.3em 0 0.3em 0.5em;
448 }
449
450 table.footnote td {
451 padding: 0.3em 0.5em;
452 }
453
454 dl {
455 margin: 0;
456 padding: 0;
457 }
458
459 dl dd {
460 margin-left: 30px;
461 }
462
463 blockquote {
464 margin: 0 0 0 30px;
465 padding: 0;
466 }
467
468 ul, ol {
469 /* Matches the 30px from the narrow-screen "li > ul" selector below */
470 margin: 10px 0 10px 30px;
471 padding: 0;
472 }
473
474 pre {
475 background: #EEE;
476 padding: 7px 30px;
477 margin: 15px 0px;
478 line-height: 1.3em;
479 }
480
481 div.viewcode-block:target {
482 background: #ffd;
483 }
484
485 dl pre, blockquote pre, li pre {
486 margin-left: 0;
487 padding-left: 30px;
488 }
489
490 dl dl pre {
491 margin-left: -90px;
492 padding-left: 90px;
493 }
494
495 tt, code {
496 background-color: #ecf0f3;
497 color: #222;
498 /* padding: 1px 2px; */
499 }
500
501 tt.xref, code.xref, a tt {
502 background-color: #FBFBFB;
503 border-bottom: 1px solid #fff;
504 }
505
506 a.reference {
507 text-decoration: none;
508 border-bottom: 1px dotted #004B6B;
509 }
510
511 /* Don't put an underline on images */
512 a.image-reference, a.image-reference:hover {
513 border-bottom: none;
514 }
515
516 a.reference:hover {
517 border-bottom: 1px solid #6D4100;
518 }
519
520 a.footnote-reference {
521 text-decoration: none;
522 font-size: 0.7em;
523 vertical-align: top;
524 border-bottom: 1px dotted #004B6B;
525 }
526
527 a.footnote-reference:hover {
528 border-bottom: 1px solid #6D4100;
529 }
530
531 a:hover tt, a:hover code {
532 background: #EEE;
533 }
534
535
536 @media screen and (max-width: 870px) {
537
538 div.sphinxsidebar {
539 display: none;
540 }
541
542 div.document {
543 width: 100%;
544
545 }
546
547 div.documentwrapper {
548 margin-left: 0;
549 margin-top: 0;
550 margin-right: 0;
551 margin-bottom: 0;
552 }
553
554 div.bodywrapper {
555 margin-top: 0;
556 margin-right: 0;
557 margin-bottom: 0;
558 margin-left: 0;
559 }
560
561 ul {
562 margin-left: 0;
563 }
564
565 li > ul {
566 /* Matches the 30px from the "ul, ol" selector above */
567 margin-left: 30px;
568 }
569
570 .document {
571 width: auto;
572 }
573
574 .footer {
575 width: auto;
576 }
577
578 .bodywrapper {
579 margin: 0;
580 }
581
582 .footer {
583 width: auto;
584 }
585
586 .github {
587 display: none;
588 }
589
590
591
592 }
593
594
595
596 @media screen and (max-width: 875px) {
597
598 body {
599 margin: 0;
600 padding: 20px 30px;
601 }
602
603 div.documentwrapper {
604 float: none;
605 background: #fff;
606 }
607
608 div.sphinxsidebar {
609 display: block;
610 float: none;
611 width: 102.5%;
612 margin: 50px -30px -20px -30px;
613 padding: 10px 20px;
614 background: #333;
615 color: #FFF;
616 }
617
618 div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,
619 div.sphinxsidebar h3 a {
620 color: #fff;
621 }
622
623 div.sphinxsidebar a {
624 color: #AAA;
625 }
626
627 div.sphinxsidebar p.logo {
628 display: none;
629 }
630
631 div.document {
632 width: 100%;
633 margin: 0;
634 }
635
636 div.footer {
637 display: none;
638 }
639
640 div.bodywrapper {
641 margin: 0;
642 }
643
644 div.body {
645 min-height: 0;
646 padding: 0;
647 }
648
649 .rtd_doc_footer {
650 display: none;
651 }
652
653 .document {
654 width: auto;
655 }
656
657 .footer {
658 width: auto;
659 }
660
661 .footer {
662 width: auto;
663 }
664
665 .github {
666 display: none;
667 }
668 }
669
670
671 /* misc. */
672
673 .revsys-inline {
674 display: none!important;
675 }
676
677 /* Make nested-list/multi-paragraph items look better in Releases changelog
678 * pages. Without this, docutils' magical list fuckery causes inconsistent
679 * formatting between different release sub-lists.
680 */
681 div#changelog > div.section > ul > li > p:only-child {
682 margin-bottom: 0;
683 }
684
685 /* Hide fugly table cell borders in ..bibliography:: directive output */
686 table.docutils.citation, table.docutils.citation td, table.docutils.citation th {
687 border: none;
688 /* Below needed in some edge cases; if not applied, bottom shadows appear */
689 -moz-box-shadow: none;
690 -webkit-box-shadow: none;
691 box-shadow: none;
692 }
693
694 code {
695 background-color: #eee;
696 }
697 code span.pre {
698 padding: 0px 4px;
699 }
700
701 dl {
702 margin: 3em 0;
703 }
704
705 div.note {
706 background-color: #dceef3;
707 border: 1px solid #85aabf;
708 }
709
710 dt:target, .highlighted {
711 background-color: #fbe54e;
712 }
0 .. include:: ../CHANGES.txt
0 # -*- coding: utf-8 -*-
1 #
2 # mockito-python documentation build configuration file, created by
3 # sphinx-quickstart on Tue Apr 26 14:00:19 2016.
4 #
5 # This file is execfile()d with the current directory set to its
6 # containing dir.
7 #
8 # Note that not all possible configuration values are present in this
9 # autogenerated file.
10 #
11 # All configuration values have a default; values that are commented out
12 # serve to show the default.
13
14 import sys
15 import os
16 import pkg_resources
17
18 # If extensions (or modules to document with autodoc) are in another directory,
19 # add these directories to sys.path here. If the directory is relative to the
20 # documentation root, use os.path.abspath to make it absolute, like shown here.
21 #sys.path.insert(0, os.path.abspath('.'))
22
23 # -- General configuration ------------------------------------------------
24
25 # If your documentation needs a minimal Sphinx version, state it here.
26 #needs_sphinx = '1.0'
27
28 # Add any Sphinx extension module names here, as strings. They can be
29 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
30 # ones.
31 extensions = [
32 'sphinx.ext.autodoc',
33 'sphinx.ext.todo',
34 # 'sphinx.ext.githubpages',
35 ]
36
37 # Add any paths that contain templates here, relative to this directory.
38 templates_path = ['_templates']
39
40 # The suffix(es) of source filenames.
41 # You can specify multiple suffix as a list of string:
42 # source_suffix = ['.rst', '.md']
43 source_suffix = '.rst'
44
45 # The encoding of source files.
46 #source_encoding = 'utf-8-sig'
47
48 # The master toctree document.
49 master_doc = 'index'
50
51 # General information about the project.
52 project = u'mockito-python'
53 copyright = u'2016, Szczepan Faber, Serhiy Oplakanets, herr.kaste'
54 author = u'Szczepan Faber, Serhiy Oplakanets, herr.kaste'
55
56 # The version info for the project you're documenting, acts as replacement for
57 # |version| and |release|, also used in various other places throughout the
58 # built documents.
59 #
60 # The short X.Y version.
61 # version = u'0.6'
62 # The full version, including alpha/beta/rc tags.
63 # release = u'0.6.1'
64
65 try:
66 release = pkg_resources.get_distribution('mockito').version
67 except pkg_resources.DistributionNotFound:
68 print('mockito must be installed to build the documentation.')
69 print('Install from source using `pip install -e .` in a virtualenv.')
70 sys.exit(1)
71
72 if 'dev' in release:
73 release = ''.join(release.partition('dev')[:2])
74
75 version = '.'.join(release.split('.')[:2])
76
77 # The language for content autogenerated by Sphinx. Refer to documentation
78 # for a list of supported languages.
79 #
80 # This is also used if you do content translation via gettext catalogs.
81 # Usually you set "language" from the command line for these cases.
82 language = None
83
84 # There are two options for replacing |today|: either, you set today to some
85 # non-false value, then it is used:
86 #today = ''
87 # Else, today_fmt is used as the format for a strftime call.
88 #today_fmt = '%B %d, %Y'
89
90 # List of patterns, relative to source directory, that match files and
91 # directories to ignore when looking for source files.
92 # This patterns also effect to html_static_path and html_extra_path
93 exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
94
95 # The reST default role (used for this markup: `text`) to use for all
96 # documents.
97 #default_role = None
98
99 # If true, '()' will be appended to :func: etc. cross-reference text.
100 #add_function_parentheses = True
101
102 # If true, the current module name will be prepended to all description
103 # unit titles (such as .. function::).
104 #add_module_names = True
105
106 # If true, sectionauthor and moduleauthor directives will be shown in the
107 # output. They are ignored by default.
108 #show_authors = False
109
110 # The name of the Pygments (syntax highlighting) style to use.
111 pygments_style = 'sphinx'
112
113 # A list of ignored prefixes for module index sorting.
114 #modindex_common_prefix = []
115
116 # If true, keep warnings as "system message" paragraphs in the built documents.
117 #keep_warnings = False
118
119 # If true, `todo` and `todoList` produce output, else they produce nothing.
120 todo_include_todos = True
121
122
123 # -- Options for HTML output ----------------------------------------------
124
125 # The theme to use for HTML and HTML Help pages. See the documentation for
126 # a list of builtin themes.
127 html_theme = 'alabaster'
128
129 # Theme options are theme-specific and customize the look and feel of a theme
130 # further. For a list of options available for each theme, see the
131 # documentation.
132 #html_theme_options = {}
133
134 # Add any paths that contain custom themes here, relative to this directory.
135 #html_theme_path = []
136
137 # The name for this set of Sphinx documents.
138 # "<project> v<release> documentation" by default.
139 #html_title = u'mockito-python v0.6.1'
140
141 # A shorter title for the navigation bar. Default is the same as html_title.
142 #html_short_title = None
143
144 # The name of an image file (relative to this directory) to place at the top
145 # of the sidebar.
146 #html_logo = None
147
148 # The name of an image file (relative to this directory) to use as a favicon of
149 # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
150 # pixels large.
151 #html_favicon = None
152
153 # Add any paths that contain custom static files (such as style sheets) here,
154 # relative to this directory. They are copied after the builtin static files,
155 # so a file named "default.css" will overwrite the builtin "default.css".
156 html_static_path = ['_static']
157
158 # Add any extra paths that contain custom files (such as robots.txt or
159 # .htaccess) here, relative to this directory. These files are copied
160 # directly to the root of the documentation.
161 #html_extra_path = []
162
163 # If not None, a 'Last updated on:' timestamp is inserted at every page
164 # bottom, using the given strftime format.
165 # The empty string is equivalent to '%b %d, %Y'.
166 #html_last_updated_fmt = None
167
168 # If true, SmartyPants will be used to convert quotes and dashes to
169 # typographically correct entities.
170 #html_use_smartypants = True
171
172 # Custom sidebar templates, maps document names to template names.
173 #html_sidebars = {}
174 html_sidebars = { '**': ['localtoc.html', 'relations.html', 'searchbox.html'], }
175
176 # Additional templates that should be rendered to pages, maps page names to
177 # template names.
178 #html_additional_pages = {}
179
180 # If false, no module index is generated.
181 #html_domain_indices = True
182
183 # If false, no index is generated.
184 #html_use_index = True
185
186 # If true, the index is split into individual pages for each letter.
187 #html_split_index = False
188
189 # If true, links to the reST sources are added to the pages.
190 #html_show_sourcelink = True
191
192 # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
193 #html_show_sphinx = True
194
195 # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
196 #html_show_copyright = True
197
198 # If true, an OpenSearch description file will be output, and all pages will
199 # contain a <link> tag referring to it. The value of this option must be the
200 # base URL from which the finished HTML is served.
201 #html_use_opensearch = ''
202
203 # This is the file name suffix for HTML files (e.g. ".xhtml").
204 #html_file_suffix = None
205
206 # Language to be used for generating the HTML full-text search index.
207 # Sphinx supports the following languages:
208 # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
209 # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
210 #html_search_language = 'en'
211
212 # A dictionary with options for the search language support, empty by default.
213 # 'ja' uses this config value.
214 # 'zh' user can custom change `jieba` dictionary path.
215 #html_search_options = {'type': 'default'}
216
217 # The name of a javascript file (relative to the configuration directory) that
218 # implements a search results scorer. If empty, the default will be used.
219 #html_search_scorer = 'scorer.js'
220
221 # Output file base name for HTML help builder.
222 htmlhelp_basename = 'mockito-pythondoc'
223
224 # -- Options for LaTeX output ---------------------------------------------
225
226 latex_elements = {
227 # The paper size ('letterpaper' or 'a4paper').
228 #'papersize': 'letterpaper',
229
230 # The font size ('10pt', '11pt' or '12pt').
231 #'pointsize': '10pt',
232
233 # Additional stuff for the LaTeX preamble.
234 #'preamble': '',
235
236 # Latex figure (float) alignment
237 #'figure_align': 'htbp',
238 }
239
240 # Grouping the document tree into LaTeX files. List of tuples
241 # (source start file, target name, title,
242 # author, documentclass [howto, manual, or own class]).
243 latex_documents = [
244 (master_doc, 'mockito-python.tex', u'mockito-python Documentation',
245 u'Szczepan Faber, Serhiy Oplakanets, herr.kaste', 'manual'),
246 ]
247
248 # The name of an image file (relative to this directory) to place at the top of
249 # the title page.
250 #latex_logo = None
251
252 # For "manual" documents, if this is true, then toplevel headings are parts,
253 # not chapters.
254 #latex_use_parts = False
255
256 # If true, show page references after internal links.
257 #latex_show_pagerefs = False
258
259 # If true, show URL addresses after external links.
260 #latex_show_urls = False
261
262 # Documents to append as an appendix to all manuals.
263 #latex_appendices = []
264
265 # If false, no module index is generated.
266 #latex_domain_indices = True
267
268
269 # -- Options for manual page output ---------------------------------------
270
271 # One entry per manual page. List of tuples
272 # (source start file, name, description, authors, manual section).
273 man_pages = [
274 (master_doc, 'mockito-python', u'mockito-python Documentation',
275 [author], 1)
276 ]
277
278 # If true, show URL addresses after external links.
279 #man_show_urls = False
280
281
282 # -- Options for Texinfo output -------------------------------------------
283
284 # Grouping the document tree into Texinfo files. List of tuples
285 # (source start file, target name, title, author,
286 # dir menu entry, description, category)
287 texinfo_documents = [
288 (master_doc, 'mockito-python', u'mockito-python Documentation',
289 author, 'mockito-python', 'One line description of project.',
290 'Miscellaneous'),
291 ]
292
293 # Documents to append as an appendix to all manuals.
294 #texinfo_appendices = []
295
296 # If false, no module index is generated.
297 #texinfo_domain_indices = True
298
299 # How to display URL addresses: 'footnote', 'no', or 'inline'.
300 #texinfo_show_urls = 'footnote'
301
302 # If true, do not generate a @detailmenu in the "Top" node's menu.
303 #texinfo_no_detailmenu = False
0 .. mockito-python documentation master file, created by
1 sphinx-quickstart on Tue Apr 26 14:00:19 2016.
2 You can adapt this file completely to your liking, but it should at least
3 contain the root `toctree` directive.
4
5 .. module:: mockito
6
7 Mockito is a spying framework originally based on the Java library with the same name.
8
9 .. image:: https://travis-ci.org/kaste/mockito-python.svg?branch=master
10 :target: https://travis-ci.org/kaste/mockito-python
11
12
13 Install
14 -------
15
16 .. code-block:: python
17
18 pip install mockito
19
20 If you already use `pytest`, consider using the plugin `pytest-mockito <https://github.com/kaste/pytest-mockito>`_.
21
22
23 Use
24 ---
25
26 .. code-block:: python
27
28 from mockito import when, mock, unstub
29
30 when(os.path).exists('/foo').thenReturn(True)
31
32 # or:
33 import requests # the famous library
34 # you actually want to return a Response-like obj, we'll fake it
35 response = mock({'status_code': 200, 'text': 'Ok'})
36 when(requests).get(...).thenReturn(response)
37
38 # use it
39 requests.get('http://google.com/')
40
41 # clean up
42 unstub()
43
44
45 Features
46 --------
47
48 Super easy to set up different answers.
49
50 ::
51
52 # Well, you know the internet
53 when(requests).get(...).thenReturn(mock({'status': 501})) \
54 .thenRaise(Timeout("I'm flaky")) \
55 .thenReturn(mock({'status': 200, 'text': 'Ok'}))
56
57 State-of-the-art, high-five argument matchers::
58
59 # Use the Ellipsis, if you don't care
60 when(deferred).defer(...).thenRaise(Timeout)
61
62 # Or **kwargs
63 from mockito import kwargs # or KWARGS
64 when(requests).get('http://my-api.com/user', **kwargs)
65
66 # The usual matchers
67 from mockito import ANY, or_, not_
68 number = or_(ANY(int), ANY(float))
69 when(math).sqrt(not_(number)).thenRaise(
70 TypeError('argument must be a number'))
71
72 No need to `verify` (`assert_called_with`) all the time::
73
74 # Different arguments, different answers
75 when(foo).bar(1).thenReturn(2)
76 when(foo).bar(2).thenReturn(3)
77
78 # but:
79 foo.bar(3) # throws immediately: unexpected invocation
80
81 # because of that you just know that when
82 # you get a `2`, you called it with `1`
83
84
85 Signature checking::
86
87 # when stubbing
88 when(requests).get() # throws immediately: TypeError url required
89
90 # when calling
91 request.get(location='http://example.com/') # TypeError
92
93
94 Read
95 ----
96
97 .. toctree::
98 :maxdepth: 1
99
100 walk-through
101 recipes
102 the-functions
103 the-matchers
104 Changelog <changes>
105
106
107
108 Report issues, contribute more documentation or give feedback at `Github <https://github.com/kaste/mockito-python>`_!
109
0 @ECHO OFF
1
2 REM Command file for Sphinx documentation
3
4 if "%SPHINXBUILD%" == "" (
5 set SPHINXBUILD=sphinx-build
6 )
7 set BUILDDIR=_build
8 set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
9 set I18NSPHINXOPTS=%SPHINXOPTS% .
10 if NOT "%PAPER%" == "" (
11 set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
12 set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
13 )
14
15 if "%1" == "" goto help
16
17 if "%1" == "help" (
18 :help
19 echo.Please use `make ^<target^>` where ^<target^> is one of
20 echo. html to make standalone HTML files
21 echo. dirhtml to make HTML files named index.html in directories
22 echo. singlehtml to make a single large HTML file
23 echo. pickle to make pickle files
24 echo. json to make JSON files
25 echo. htmlhelp to make HTML files and a HTML help project
26 echo. qthelp to make HTML files and a qthelp project
27 echo. devhelp to make HTML files and a Devhelp project
28 echo. epub to make an epub
29 echo. epub3 to make an epub3
30 echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31 echo. text to make text files
32 echo. man to make manual pages
33 echo. texinfo to make Texinfo files
34 echo. gettext to make PO message catalogs
35 echo. changes to make an overview over all changed/added/deprecated items
36 echo. xml to make Docutils-native XML files
37 echo. pseudoxml to make pseudoxml-XML files for display purposes
38 echo. linkcheck to check all external links for integrity
39 echo. doctest to run all doctests embedded in the documentation if enabled
40 echo. coverage to run coverage check of the documentation if enabled
41 echo. dummy to check syntax errors of document sources
42 goto end
43 )
44
45 if "%1" == "clean" (
46 for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
47 del /q /s %BUILDDIR%\*
48 goto end
49 )
50
51
52 REM Check if sphinx-build is available and fallback to Python version if any
53 %SPHINXBUILD% 1>NUL 2>NUL
54 if errorlevel 9009 goto sphinx_python
55 goto sphinx_ok
56
57 :sphinx_python
58
59 set SPHINXBUILD=python -m sphinx.__init__
60 %SPHINXBUILD% 2> nul
61 if errorlevel 9009 (
62 echo.
63 echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
64 echo.installed, then set the SPHINXBUILD environment variable to point
65 echo.to the full path of the 'sphinx-build' executable. Alternatively you
66 echo.may add the Sphinx directory to PATH.
67 echo.
68 echo.If you don't have Sphinx installed, grab it from
69 echo.http://sphinx-doc.org/
70 exit /b 1
71 )
72
73 :sphinx_ok
74
75
76 if "%1" == "html" (
77 %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
78 if errorlevel 1 exit /b 1
79 echo.
80 echo.Build finished. The HTML pages are in %BUILDDIR%/html.
81 goto end
82 )
83
84 if "%1" == "dirhtml" (
85 %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
86 if errorlevel 1 exit /b 1
87 echo.
88 echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
89 goto end
90 )
91
92 if "%1" == "singlehtml" (
93 %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
94 if errorlevel 1 exit /b 1
95 echo.
96 echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
97 goto end
98 )
99
100 if "%1" == "pickle" (
101 %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
102 if errorlevel 1 exit /b 1
103 echo.
104 echo.Build finished; now you can process the pickle files.
105 goto end
106 )
107
108 if "%1" == "json" (
109 %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
110 if errorlevel 1 exit /b 1
111 echo.
112 echo.Build finished; now you can process the JSON files.
113 goto end
114 )
115
116 if "%1" == "htmlhelp" (
117 %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
118 if errorlevel 1 exit /b 1
119 echo.
120 echo.Build finished; now you can run HTML Help Workshop with the ^
121 .hhp project file in %BUILDDIR%/htmlhelp.
122 goto end
123 )
124
125 if "%1" == "qthelp" (
126 %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
127 if errorlevel 1 exit /b 1
128 echo.
129 echo.Build finished; now you can run "qcollectiongenerator" with the ^
130 .qhcp project file in %BUILDDIR%/qthelp, like this:
131 echo.^> qcollectiongenerator %BUILDDIR%\qthelp\mockito-python.qhcp
132 echo.To view the help file:
133 echo.^> assistant -collectionFile %BUILDDIR%\qthelp\mockito-python.ghc
134 goto end
135 )
136
137 if "%1" == "devhelp" (
138 %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
139 if errorlevel 1 exit /b 1
140 echo.
141 echo.Build finished.
142 goto end
143 )
144
145 if "%1" == "epub" (
146 %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
147 if errorlevel 1 exit /b 1
148 echo.
149 echo.Build finished. The epub file is in %BUILDDIR%/epub.
150 goto end
151 )
152
153 if "%1" == "epub3" (
154 %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
155 if errorlevel 1 exit /b 1
156 echo.
157 echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
158 goto end
159 )
160
161 if "%1" == "latex" (
162 %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
163 if errorlevel 1 exit /b 1
164 echo.
165 echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
166 goto end
167 )
168
169 if "%1" == "latexpdf" (
170 %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
171 cd %BUILDDIR%/latex
172 make all-pdf
173 cd %~dp0
174 echo.
175 echo.Build finished; the PDF files are in %BUILDDIR%/latex.
176 goto end
177 )
178
179 if "%1" == "latexpdfja" (
180 %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
181 cd %BUILDDIR%/latex
182 make all-pdf-ja
183 cd %~dp0
184 echo.
185 echo.Build finished; the PDF files are in %BUILDDIR%/latex.
186 goto end
187 )
188
189 if "%1" == "text" (
190 %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
191 if errorlevel 1 exit /b 1
192 echo.
193 echo.Build finished. The text files are in %BUILDDIR%/text.
194 goto end
195 )
196
197 if "%1" == "man" (
198 %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
199 if errorlevel 1 exit /b 1
200 echo.
201 echo.Build finished. The manual pages are in %BUILDDIR%/man.
202 goto end
203 )
204
205 if "%1" == "texinfo" (
206 %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
207 if errorlevel 1 exit /b 1
208 echo.
209 echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
210 goto end
211 )
212
213 if "%1" == "gettext" (
214 %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
215 if errorlevel 1 exit /b 1
216 echo.
217 echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
218 goto end
219 )
220
221 if "%1" == "changes" (
222 %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
223 if errorlevel 1 exit /b 1
224 echo.
225 echo.The overview file is in %BUILDDIR%/changes.
226 goto end
227 )
228
229 if "%1" == "linkcheck" (
230 %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
231 if errorlevel 1 exit /b 1
232 echo.
233 echo.Link check complete; look for any errors in the above output ^
234 or in %BUILDDIR%/linkcheck/output.txt.
235 goto end
236 )
237
238 if "%1" == "doctest" (
239 %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
240 if errorlevel 1 exit /b 1
241 echo.
242 echo.Testing of doctests in the sources finished, look at the ^
243 results in %BUILDDIR%/doctest/output.txt.
244 goto end
245 )
246
247 if "%1" == "coverage" (
248 %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
249 if errorlevel 1 exit /b 1
250 echo.
251 echo.Testing of coverage in the sources finished, look at the ^
252 results in %BUILDDIR%/coverage/python.txt.
253 goto end
254 )
255
256 if "%1" == "xml" (
257 %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
258 if errorlevel 1 exit /b 1
259 echo.
260 echo.Build finished. The XML files are in %BUILDDIR%/xml.
261 goto end
262 )
263
264 if "%1" == "pseudoxml" (
265 %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
266 if errorlevel 1 exit /b 1
267 echo.
268 echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
269 goto end
270 )
271
272 if "%1" == "dummy" (
273 %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
274 if errorlevel 1 exit /b 1
275 echo.
276 echo.Build finished. Dummy builder generates no files.
277 goto end
278 )
279
280 :end
0 TL;DR
1 -----
2
3
4 ::
5
6 >>> from mockito import *
7 >>> myMock = mock()
8 >>> when(myMock).getStuff().thenReturn('stuff')
9 <mockito.invocation.AnswerSelector object at 0x00CA0BB0>
10 >>> myMock.getStuff()
11 'stuff'
12 >>> verify(myMock).getStuff()
13
14 >>> when(myMock).doSomething().thenRaise(Exception('Did a bad thing'))
15 <mockito.invocation.AnswerSelector object at 0x00CA0C10>
16 >>> myMock.doSomething()
17 Traceback (most recent call last):
18 <...>
19 Exception: Did a bad thing
20
21 No difference whatsoever when you mock modules
22
23 ::
24
25 >>> import os.path
26 >>> when(os.path).exists('somewhere/somewhat').thenReturn(True)
27 <mockito.invocation.AnswerSelector object at 0x00D394F0>
28 >>> when(os.path).exists('somewhere/something').thenReturn(False)
29 <mockito.invocation.AnswerSelector object at 0x00C7D1B0>
30 >>> os.path.exists('somewhere/somewhat')
31 True
32 >>> os.path.exists('somewhere/something')
33 False
34 >>> os.path.exists('another_place')
35 Traceback (most recent call last):
36 <...>
37 mockito.invocation.InvocationError: You called exists with ('another_place',) as
38 arguments but we did not expect that.
39
40 >>> when(os.path).exist('./somewhat').thenReturn(True)
41 Traceback (most recent call last):
42 <...>
43 mockito.invocation.InvocationError: You tried to stub a method 'exist' the objec
44 t (<module 'ntpath' from ...>) doesn't have.
45
46 If that's too strict, you can change it
47
48 ::
49
50 >>> when(os.path, strict=False).exist('another_place').thenReturn('well, nice he
51 re')
52 <mockito.invocation.AnswerSelector object at 0x00D429B0>
53 >>> os.path.exist('another_place')
54 'well, nice here'
55 >>> os.path.exist('and here?')
56 >>>
57
58 No surprise, you can do the same with your classes
59
60 ::
61
62 >>> class Dog(object):
63 ... def bark(self):
64 ... return "Wau"
65 ...
66 >>> when(Dog).bark().thenReturn('Miau!')
67 <mockito.invocation.AnswerSelector object at 0x00D42390>
68 >>> rex = Dog()
69 >>> rex.bark()
70 'Miau!'
71
72 or just with instances, first unstub
73
74 ::
75
76 >>> unstub()
77 >>> rex.bark()
78 'Wau'
79
80 then do
81
82 ::
83
84 >>> when(rex).bark().thenReturn('Grrrrr').thenReturn('Wuff')
85 <mockito.invocation.AnswerSelector object at 0x00D48790>
86
87 and get something different on consecutive calls
88
89 ::
90
91 >>> rex.bark()
92 'Grrrrr'
93 >>> rex.bark()
94 'Wuff'
95 >>> rex.bark()
96 'Wuff'
97
98 and since you stubbed an instance, a different instance will not be stubbed
99
100 ::
101
102 >>> bello = Dog()
103 >>> bello.bark()
104 'Wau'
105
106 You have 4 modifiers when verifying
107
108 ::
109
110 >>> verify(rex, times=3).bark()
111 >>> verify(rex, atleast=1).bark()
112 >>> verify(rex, atmost=3).bark()
113 >>> verify(rex, between=[1,3]).bark()
114 >>>
115
116 Finally, we have two matchers
117
118 ::
119
120 >>> myMock = mock()
121 >>> when(myMock).do(any(int)).thenReturn('A number')
122 <mockito.invocation.AnswerSelector object at 0x00D394B0>
123 >>> when(myMock).do(any(str)).thenReturn('A string')
124 <mockito.invocation.AnswerSelector object at 0x00D39E70>
125 >>> myMock.do(2)
126 'A number'
127 >>> myMock.do('times')
128 'A string'
129
130 >>> verify(myMock).do(any(int))
131 >>> verify(myMock).do(any(str))
132 >>> verify(myMock).do(contains('time'))
133
134 >>> exit()
135
136 .. toctree::
137 :maxdepth: 2
138
0 .. module:: mockito
1
2
3 Recipes
4 =======
5
6
7 Classes as factories
8 --------------------
9
10 We want to test the following code::
11
12 import requests
13
14 def fetch(url):
15 session = requests.Session()
16 return session.get(url)
17
18 In a traditional sense this code is not designed for *testability*. But we don't care here.
19
20 Python has no `new` keyword to get fresh instances from classes. Man, that was a good decision, Guido! So the uppercase `S` in `requests.Session()` doesn't have to stop us in any way. It looks like a function call, and we treat it like such: The plan is to replace `Session` with a factory function that returns a (mocked) session::
21
22 from mockito import when, mock, verifyStubbedInvocationsAreUsed
23
24 def test_fetch(unstub):
25 url = 'http://example.com/'
26 response = mock({'text': 'Ok'}, spec=requests.Response)
27 # remember: `mock` here just creates an empty object specced after
28 # requests.Session
29 session = mock(requests.Session)
30 # `when` here configures the mock
31 when(session).get(url).thenReturn(response)
32 # `when` *patches* the globally available *requests* module
33 when(requests).Session().thenReturn(session) # <=
34
35 res = fetch(url)
36 assert res.text == 'Ok'
37
38 # no need to verify anything here, if we get the expected response
39 # back, `url` must have been passed through the system, otherwise
40 # mockito would have thrown.
41 # We *could* ensure that our mocks are actually used, if we want:
42 verifyStubbedInvocationsAreUsed()
43
44
45 Faking magic methods
46 --------------------
47
48 We want to test the following code::
49
50 import requests
51
52 def fetch_2(url):
53 with requests.Session() as session:
54 return session.get(url)
55
56 It's basically the same problem, but we need to add support for the context manager, the `with` interface::
57
58 from mockito import when, mock, args
59
60 def test_fetch_with(unstub):
61 url = 'http://example.com/'
62 response = mock({'text': 'Ok'}, spec=requests.Response)
63
64 session = mock(requests.Session)
65 when(session).get(url).thenReturn(response)
66 when(session).__enter__().thenReturn(session) # <=
67 when(session).__exit__(*args) # <=
68
69 when(requests).Session().thenReturn(session)
70
71 res = fetch_2(url)
72 assert res.text == 'Ok'
73
74
0 .. module:: mockito
1
2
3 The functions
4 =============
5
6 Stable entrypoints are: :func:`when`, :func:`mock`, :func:`unstub`, :func:`verify`, :func:`spy`. Experimental or new function introduces with v1.0.x are: :func:`when2`, :func:`expect`, :func:`verifyNoUnwantedInteractions`, :func:`verifyStubbedInvocationsAreUsed`, :func:`patch`
7
8 .. autofunction:: when
9 .. autofunction:: when2
10 .. autofunction:: patch
11 .. autofunction:: expect
12 .. autofunction:: mock
13 .. autofunction:: unstub
14 .. autofunction:: forget_invocations
15 .. autofunction:: spy
16 .. autofunction:: spy2
17
18 This looks like a plethora of verification functions, and especially since you often don't need to `verify` at all.
19
20 .. autofunction:: verify
21 .. autofunction:: verifyNoMoreInteractions
22 .. autofunction:: verifyZeroInteractions
23 .. autofunction:: verifyNoUnwantedInteractions
24 .. autofunction:: verifyStubbedInvocationsAreUsed
25
26
0 The matchers
1 ============
2
3
4 .. automodule:: mockito.matchers
5 :members:
0 The Walk-through
1 ================
2
3 The 90% use case is that want to stub out a side effect. This is also known as (monkey-)patching. With mockito, it's::
4
5 from mockito import when
6
7 # stub `os.path.exists`
8 when(os.path).exists('/foo').thenReturn(True)
9
10 os.path.exists('/foo') # => True
11 os.path.exists('/bar') # -> throws unexpected invocation
12
13 So in difference to traditional patching, in mockito you always specify concrete arguments (a call signature), and its outcome, usually a return value via `thenReturn` or a raised exception via `thenRaise`. That effectively turns function calls into constants for the time of the test.
14
15 Do **not** forget to :func:`unstub` of course!
16
17 ::
18
19 from mockito import unstub
20 unstub() # restore os.path module
21
22
23 Now we mix global module patching with mocks. We want to test the following function using the fab `requests` library::
24
25 import requests
26
27 def get_text(url):
28 res = requests.get(url)
29 if 200 <= res.status_code < 300:
30 return res.text
31 return None
32
33 How, dare, we did not inject our dependencies! Obviously we can get over that by patching at the module level like before::
34
35 when(requests).get('https://example.com/api').thenReturn(...)
36
37 But what should we return? We know it's a `requests.Response` object, (Actually I know this bc I typed this in the ipython REPL first.) But how to construct such a `Response`, its `__init__` doesn't even take any arguments?
38
39 Should we actually use a 'real' response object? No, we fake it using :func:`mock`.
40
41 ::
42
43 # setup
44 response = mock({
45 'status_code': 200,
46 'text': 'Ok'
47 }, spec=requests.Response)
48 when(requests).get('https://example.com/api').thenReturn(response)
49
50 # run
51 assert get_text('https://example.com/api') == 'Ok'
52
53 # done!
54
55 Say you want to mock the class Dog::
56
57 class Dog(object):
58 def bark(self):
59 return 'Wuff'
60
61
62 # either mock the class
63 when(Dog).bark().thenReturn('Miau!')
64 # now all instances have a different behavior
65 rex = Dog()
66 assert rex.bark() == 'Miau!'
67
68 # or mock a concrete instance
69 when(rex).bark().thenReturn('Grrrr')
70 assert rex.bark() == 'Grrrr'
71 # a different dog will still 'Miau!'
72 assert Dog().bark() == 'Miau!'
73
74 # be sure to call unstub() once in while
75 unstub()
76
77
78 Sure, you can verify your interactions::
79
80 from mockito import verify
81 # once again
82 rex = Dog()
83 when(rex).bark().thenReturn('Grrrr')
84
85 rex.bark()
86 rex.bark()
87
88 # `times` defaults to 1
89 verify(rex, times=2).bark()
90
91
92 In general mockito is very picky::
93
94 # this will fail because `Dog` has no method named `waggle`
95 when(rex).waggle().thenReturn('Nope')
96 # this will fail because `bark` does not take any arguments
97 when(rex).bark('Grrr').thenReturn('Nope')
98
99
100 # given this function
101 def bark(sound, post='!'):
102 return sound + post
103
104 from mockito import kwargs
105 when(main).bark('Grrr', **kwargs).thenReturn('Nope')
106
107 # now this one will fail
108 bark('Grrr') # because there are no keyword arguments used
109 # this one will fail because `then` does not match the function signature
110 bark('Grrr', then='!!')
111 # this one will go
112 bark('Grrr', post='?')
113
114 # there is also an args matcher
115 def add_tasks(*tasks, verbose=False):
116 pass
117
118 from mockito import args
119 # If you omit the `thenReturn` it will just return `None`
120 when(main).add_tasks(*args)
121
122 add_tasks('task1', 'task2') # will go
123 add_tasks() # will fail
124 add_tasks('task1', verbose=True) # will fail too
125
126 # On Python 3 you can also use `...`
127 when(main).add_tasks(...)
128 # when(main).add_tasks(Ellipsis) on Python 2
129
130 add_tasks('task1') # will go
131 add_tasks(verbose=True) # will go
132 add_tasks('task1', verbose=True) # will go
133 add_tasks() # will go
134
135
136 To start with an empty stub use :func:`mock`::
137
138 from mockito import mock
139
140 obj = mock()
141
142 # pass it around, eventually it will be used
143 obj.say('Hi')
144
145 # back in the tests, verify the interactions
146 verify(obj).say('Hi')
147
148 # by default all invoked methods take any arguments and return None
149 # you can configure your expected method calls with the ususal `when`
150 when(obj).say('Hi').thenReturn('Ho')
151
152 # There is also a shortcut to set some attributes
153 obj = mock({
154 'hi': 'ho'
155 })
156
157 assert obj.hi == 'ho'
158
159 # This would work for methods as well; in this case
160 obj = mock({
161 'say': lambda _: 'Ho'
162 })
163
164 # But you don't have any argument and signature matching
165 assert obj.say('Anything') == 'Ho'
166
167 # At least you can verify your calls
168 verify(obj).say(...)
169
170 # Btw, you can make screaming strict mocks::
171 obj = mock(strict=True) # every unconfigured, unexpected call will raise
172
173
174 You can use an empty stub specced against a concrete class::
175
176 # Given the above `Dog`
177 rex = mock(Dog)
178
179 # Now you can stub out any known method on `Dog` but other will throw
180 when(rex).bark().thenReturn('Miau')
181 # this one will fail
182 when(rex).waggle()
183
184 # These mocks are in general very strict, so even this will fail
185 rex.health # unconfigured attribute
186
187 # Of course you can just set it in a setup routine
188 rex.health = 121
189
190 # Or again preconfigure
191 rex = mock({'health': 121}, spec=Dog)
192
193 # preconfigure stubbed method
194 rex = mock({'bark': lambda sound: 'Miau'}, spec=Dog)
195
196 # as you specced the mock, you get at least function signature matching
197 # `bark` does not take any arguments so
198 rex.bark('sound') # will throw TypeError
199
200 # Btw, you can make loose specced mocks::
201 rex = mock(Dog, strict=False)
202
203
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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.
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.
1919
2020 '''Mockito is a Test Spy framework.'''
2121
2222
23 from mockito import mock, verify, verifyNoMoreInteractions, verifyZeroInteractions, when, unstub, ArgumentError
24 import inorder
25 from spying import spy
26 from verification import VerificationError
23 from .mockito import (
24 when,
25 when2,
26 patch,
27 expect,
28 unstub,
29 forget_invocations,
30 verify,
31 verifyNoMoreInteractions,
32 verifyZeroInteractions,
33 verifyNoUnwantedInteractions,
34 verifyStubbedInvocationsAreUsed,
35 ArgumentError,
36 )
37 from . import inorder
38 from .spying import spy, spy2
39 from .mocking import mock
40 from .verification import VerificationError
2741
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
42 from .matchers import * # noqa: F401 F403
43 from .matchers import any, contains, times
44 from .verification import never
3245
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 ]
46 __version__ = '1.2.0'
47
48 __all__ = [
49 'mock',
50 'spy',
51 'spy2',
52 'when',
53 'when2',
54 'patch',
55 'expect',
56 'verify',
57 'verifyNoMoreInteractions',
58 'verifyZeroInteractions',
59 'verifyNoUnwantedInteractions',
60 'verifyStubbedInvocationsAreUsed',
61 'inorder',
62 'unstub',
63 'forget_invocations',
64 'VerificationError',
65 'ArgumentError',
66 'any', # compatibility
67 'contains', # compatibility
68 'never', # compatibility
69 'times', # deprecated
70 ]
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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.
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.
1919
20 from mockito import verify as verify_main
21
22 __author__ = "Serhiy Oplakanets <[email protected]>"
20 from .mockito import verify as verify_main
2321
2422
2523 def verify(object, *args, **kwargs):
26 kwargs['inorder'] = True
27 return verify_main(object, *args, **kwargs)
24 kwargs['inorder'] = True
25 return verify_main(object, *args, **kwargs)
2826
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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):
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 . import matchers
21 import operator
22 from . import signature
23 from . import verification as verificationModule
24 from .utils import contains_strict
25
26 from collections import deque
27 import functools
28
29
30 class InvocationError(AttributeError):
2431 pass
2532
33
34 __tracebackhide__ = operator.methodcaller(
35 "errisinstance",
36 (InvocationError, verificationModule.VerificationError)
37 )
38
39
2640 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
41 def __init__(self, mock, method_name):
42 self.mock = mock
43 self.method_name = method_name
44 self.strict = mock.strict
45
46 self.params = ()
47 self.named_params = {}
48
49 def _remember_params(self, params, named_params):
50 self.params = params
51 self.named_params = named_params
52
53 def __repr__(self):
54 args = [repr(p) if p is not Ellipsis else '...'
55 for p in self.params]
56 kwargs = ["%s=%r" % (key, val)
57 if key is not matchers.KWARGS_SENTINEL else '**kwargs'
58 for key, val in self.named_params.items()]
59 params = ", ".join(args + kwargs)
60 return "%s(%s)" % (self.method_name, params)
61
62
63 class RememberedInvocation(Invocation):
64 def __init__(self, mock, method_name):
65 super(RememberedInvocation, self).__init__(mock, method_name)
66 self.verified = False
67 self.verified_inorder = False
68
69 def ensure_mocked_object_has_method(self, method_name):
70 if not self.mock.has_method(method_name):
71 raise InvocationError(
72 "You tried to call a method '%s' the object (%s) doesn't "
73 "have." % (method_name, self.mock.mocked_obj))
74
75 def ensure_signature_matches(self, method_name, args, kwargs):
76 sig = self.mock.get_signature(method_name)
77 if not sig:
78 return
79
80 signature.match_signature(sig, args, kwargs)
81
82 def __call__(self, *params, **named_params):
83 if self.strict:
84 self.ensure_mocked_object_has_method(self.method_name)
85 self.ensure_signature_matches(
86 self.method_name, params, named_params)
87
88 self._remember_params(params, named_params)
89 self.mock.remember(self)
90
91 for matching_invocation in self.mock.stubbed_invocations:
92 if matching_invocation.matches(self):
93 matching_invocation.should_answer(self)
94 return matching_invocation.answer_first(
95 *params, **named_params)
96
97 if self.strict:
98 stubbed_invocations = [
99 invoc
100 for invoc in self.mock.stubbed_invocations
101 if invoc.method_name == self.method_name
102 ]
103 raise InvocationError(
104 """
105 Called but not expected:
106
107 %s
108
109 Stubbed invocations are:
110
111 %s
112
113 """
114 % (
115 self,
116 "\n ".join(
117 str(invoc) for invoc in reversed(stubbed_invocations)
118 )
119 )
120 )
121
122 return None
123
124
125 class RememberedProxyInvocation(Invocation):
126 '''Remeber params and proxy to method of original object.
127
128 Calls method on original object and returns it's return value.
129 '''
130 def __init__(self, mock, method_name):
131 super(RememberedProxyInvocation, self).__init__(mock, method_name)
132 self.verified = False
133 self.verified_inorder = False
134
135 def __call__(self, *params, **named_params):
136 self._remember_params(params, named_params)
137 self.mock.remember(self)
138 obj = self.mock.spec
139 try:
140 method = getattr(obj, self.method_name)
141 except AttributeError:
142 raise AttributeError(
143 "You tried to call method '%s' which '%s' instance does not "
144 "have." % (self.method_name, obj))
145 return method(*params, **named_params)
146
147
47148 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)
149 @staticmethod
150 def compare(p1, p2):
151 if isinstance(p1, matchers.Matcher):
152 if not p1.matches(p2):
153 return False
154 elif p1 != p2:
155 return False
156 return True
157
158 def _remember_params(self, params, named_params):
159 if (
160 contains_strict(params, Ellipsis)
161 and (params[-1] is not Ellipsis or named_params)
162 ):
163 raise TypeError('Ellipsis must be the last argument you specify.')
164
165 if contains_strict(params, matchers.args):
166 raise TypeError('args must be used as *args')
167
168 if (
169 contains_strict(params, matchers.kwargs)
170 or contains_strict(params, matchers.KWARGS_SENTINEL)
171 ):
172 raise TypeError('kwargs must be used as **kwargs')
173
174 def wrap(p):
175 if p is any or p is matchers.any_:
176 return matchers.any_()
177 return p
178
179 self.params = tuple(wrap(p) for p in params)
180 self.named_params = {k: wrap(v) for k, v in named_params.items()}
181
182 # Note: matches(a, b) does not imply matches(b, a) because
183 # the left side might contain wildcards (like Ellipsis) or matchers.
184 # In its current form the right side is a concrete call signature.
185 def matches(self, invocation): # noqa: C901 (too complex)
186 if self.method_name != invocation.method_name:
187 return False
188
189 for x, p1 in enumerate(self.params):
190 # assume Ellipsis is the last thing a user declares
191 if p1 is Ellipsis:
192 return True
193
194 if p1 is matchers.ARGS_SENTINEL:
195 break
196
197 try:
198 p2 = invocation.params[x]
199 except IndexError:
200 return False
201
202 if not self.compare(p1, p2):
203 return False
204 else:
205 if len(self.params) != len(invocation.params):
206 return False
207
208 for key, p1 in sorted(
209 self.named_params.items(),
210 key=lambda k_v: 1 if k_v[0] is matchers.KWARGS_SENTINEL else 0
211 ):
212 if key is matchers.KWARGS_SENTINEL:
213 break
214
215 try:
216 p2 = invocation.named_params[key]
217 except KeyError:
218 return False
219
220 if not self.compare(p1, p2):
221 return False
222 else:
223 if len(self.named_params) != len(invocation.named_params):
224 return False
225
226 return True
227
100228
101229 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
230 def __init__(self, mock, method_name, verification):
231 super(VerifiableInvocation, self).__init__(mock, method_name)
232 self.verification = verification
233
234 def __call__(self, *params, **named_params):
235 self._remember_params(params, named_params)
236 matched_invocations = []
237 for invocation in self.mock.invocations:
238 if self.matches(invocation):
239 matched_invocations.append(invocation)
240
241 self.verification.verify(self, len(matched_invocations))
242
243 # check (real) invocations as verified
244 for invocation in matched_invocations:
245 invocation.verified = True
246
247 # check stubs as 'used'
248 if verification_has_lower_bound_of_zero(self.verification):
249 for stub in self.mock.stubbed_invocations:
250 # Remember: matches(a, b) does not imply matches(b, a)
251 # (see above!), so we check for both
252 if stub.matches(self) or self.matches(stub):
253 stub.allow_zero_invocations = True
254
255
256 def verification_has_lower_bound_of_zero(verification):
257 if (
258 isinstance(verification, verificationModule.Times)
259 and verification.wanted_count == 0
260 ):
261 return True
262
263 if (
264 isinstance(verification, verificationModule.Between)
265 and verification.wanted_from == 0
266 ):
267 return True
268
269 return False
270
271
115272 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
273 def __init__(self, mock, method_name, verification=None, strict=None):
274 super(StubbedInvocation, self).__init__(mock, method_name)
275
276 #: Holds the verification set up via `expect`.
277 #: The verification will be verified implicitly, while using this stub.
278 self.verification = verification
279
280 if strict is not None:
281 self.strict = strict
282
283 self.answers = CompositeAnswer()
284
285 #: Counts how many times this stub has been 'used'.
286 #: A stub gets used, when a real invocation matches its argument
287 #: signature, and asks for an answer.
288 self.used = 0
289
290 #: Set if `verifyStubbedInvocationsAreUsed` should pass, regardless
291 #: of any factual invocation. E.g. set by `verify(..., times=0)`
292 if verification_has_lower_bound_of_zero(verification):
293 self.allow_zero_invocations = True
294 else:
295 self.allow_zero_invocations = False
296
297
298 def ensure_mocked_object_has_method(self, method_name):
299 if not self.mock.has_method(method_name):
300 raise InvocationError(
301 "You tried to stub a method '%s' the object (%s) doesn't "
302 "have." % (method_name, self.mock.mocked_obj))
303
304 def ensure_signature_matches(self, method_name, args, kwargs):
305 sig = self.mock.get_signature(method_name)
306 if not sig:
307 return
308
309 signature.match_signature_allowing_placeholders(sig, args, kwargs)
310
311 def __call__(self, *params, **named_params):
312 if self.strict:
313 self.ensure_mocked_object_has_method(self.method_name)
314 self.ensure_signature_matches(
315 self.method_name, params, named_params)
316 self._remember_params(params, named_params)
317
318 self.mock.stub(self.method_name)
319 self.mock.finish_stubbing(self)
320 return AnswerSelector(self)
321
322 def forget_self(self):
323 self.mock.forget_stubbed_invocation(self)
324
325 def add_answer(self, answer):
326 self.answers.add(answer)
327
328 def answer_first(self, *args, **kwargs):
329 self.used += 1
330 return self.answers.answer(*args, **kwargs)
331
332 def should_answer(self, invocation):
333 # type: (RememberedInvocation) -> None
334 verification = self.verification
335 if not verification:
336 return
337
338 # This check runs before `answer_first`. We add '1' because we want
339 # to know if the verification passes if this call gets through.
340 actual_count = self.used + 1
341
342 if isinstance(verification, verificationModule.Times):
343 if actual_count > verification.wanted_count:
344 raise InvocationError(
345 "\nWanted times: %i, actual times: %i"
346 % (verification.wanted_count, actual_count))
347 elif isinstance(verification, verificationModule.AtMost):
348 if actual_count > verification.wanted_count:
349 raise InvocationError(
350 "\nWanted at most: %i, actual times: %i"
351 % (verification.wanted_count, actual_count))
352 elif isinstance(verification, verificationModule.Between):
353 if actual_count > verification.wanted_to:
354 raise InvocationError(
355 "\nWanted between: [%i, %i], actual times: %i"
356 % (verification.wanted_from,
357 verification.wanted_to,
358 actual_count))
359
360 # The way mockito's `verify` works is, that it checks off all 'real',
361 # remembered invocations, if they get verified. This is a simple
362 # mechanism so that a later `verifyNoMoreInteractions` just has to
363 # ensure that all invocations have this flag set to ``True``.
364 # For verifications set up via `expect` we want all invocations
365 # to get verified 'implicitly', on-the-go, so we set this flag here.
366 invocation.verified = True
367
368
369 def verify(self):
370 if not self.verification:
371 return
372
373 actual_count = self.used
374 self.verification.verify(self, actual_count)
375
376
377
378 def return_(value, *a, **kw):
379 return value
380
381 def raise_(exception, *a, **kw):
382 raise exception
383
384
136385 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
386 def __init__(self, invocation):
387 self.invocation = invocation
388
389 def thenReturn(self, *return_values):
390 for return_value in return_values:
391 self.__then(functools.partial(return_, return_value))
392 return self
393
394 def thenRaise(self, *exceptions):
395 for exception in exceptions:
396 self.__then(functools.partial(raise_, exception))
397 return self
398
399 def thenAnswer(self, *callables):
400 for callable in callables:
401 self.__then(callable)
402 return self
403
404 def __then(self, answer):
405 self.invocation.add_answer(answer)
406
407 def __enter__(self):
408 pass
409
410 def __exit__(self, *exc_info):
411 self.invocation.forget_self()
412
159413
160414 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
415 def __init__(self):
416 #: Container for answers, which are just ordinary callables
417 self.answers = deque()
418
419 #: Counter for the maximum answers we ever had
420 self.answer_count = 0
421
422 def __len__(self):
423 # The minimum is '1' bc we always have a default answer of 'None'
424 return max(1, self.answer_count)
425
426 def add(self, answer):
427 self.answer_count += 1
428 self.answers.append(answer)
429
430 def answer(self, *args, **kwargs):
431 if len(self.answers) == 0:
432 return None
433
434 if len(self.answers) == 1:
435 a = self.answers[0]
436 else:
437 a = self.answers.popleft()
438
439 return a(*args, **kwargs)
440
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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
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 """Argument matchers for stubbing and verifications.
21
22 In general the call signature you specify when stubbing or verifying in mockito
23 is as concrete as possible: it consists of values only::
24
25 when(os.path).exists('/foo/bar.txt').thenReturn(True)
26
27 This is for a reason. In controlled test environments, for the scope of a
28 single test, you should usually know exactly how you use a function, and what
29 you expect its outcome to be. In mockito usually (in `strict` mode) all
30 invocations you did not specify upfront will throw at call time.
31
32 If you reason about your code, the above `when` tirade turns - for the time
33 of the test - the specific stubbed function into a constant.
34
35 You can use so called argument matchers below if you can't or don't
36 want to specify a single concrete value for an argument, but a type or class of
37 possible values. E.g.::
38
39 when(os.path).exists(...).thenReturn(True)
40 when(os.path).exists(ANY).thenReturn(True)
41 when(os.path).exists(ANY(str)).thenReturn(True)
42
43 when(requests).get(ANY(str), **kwargs)
44 when(requests).get('https://example.com', ...)
45
46 when(math).sqrt(not_(_or(ANY(float), ANY(int)))).thenRaise(TypeError)
47
48 Now what you get each time is a function that up to a degree takes various
49 arguments and responds with the same outcome each time. Now that's a weird
50 thing. So use the matchers for a reason, they're powerful.
51
52 The one usage you should not care about is a loose signature when using
53 :func:`verify`. Since mockito will throw for unexpected calls, a very loose
54 `verify` should be ok::
55
56 verify(requests, times=1).get(...)
57
58
59 """
60
61 import re
62
63
64 __all__ = [
65 'and_', 'or_', 'not_',
66 'eq', 'neq',
67 'lt', 'lte',
68 'gt', 'gte',
69 'any', 'any_', 'ANY',
70 'arg_that',
71 'contains',
72 'matches',
73 'captor',
74 'times',
75 'args', 'ARGS',
76 'kwargs', 'KWARGS'
77 ]
78
79 class _ArgsSentinel(object):
80 def __repr__(self):
81 return '*args'
82
83
84 ARGS_SENTINEL = _ArgsSentinel()
85 ARGS = args = [ARGS_SENTINEL]
86 # ARGS.__doc__ = """Matches multiple positional arguments.
87
88 # Note: `args` must match at least one argument.
89
90 # Example::
91
92 # when(manager).add_tasks(1, 2, *args)
93
94 # """
95
96 KWARGS_SENTINEL = '**'
97 KWARGS = kwargs = {KWARGS_SENTINEL: '_'}
98 # KWARGS.__doc__ = """Matches multiple keyword arguments.
99
100 # Note that `kwargs` must match at least one remaining keyword argument.
101
102 # Example::
103
104 # when(requests).get('http://myapi/', **KWARGS)
105
106 # """
27107
28108 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
109 def matches(self, arg):
110 pass
111
112
113 class Any(Matcher):
114 def __init__(self, wanted_type=None):
115 self.wanted_type = wanted_type
116
117 def matches(self, arg):
118 if self.wanted_type:
119 return isinstance(arg, self.wanted_type)
120 else:
121 return True
122
123 def __repr__(self):
124 return "<Any: %s>" % self.wanted_type
125
126
127 class ValueMatcher(Matcher):
128 def __init__(self, value):
129 self.value = value
130
131 def __repr__(self):
132 return "<%s: %s>" % (self.__class__.__name__, self.value)
133
134
135 class Eq(ValueMatcher):
136 def matches(self, arg):
137 return arg == self.value
138
139
140 class Neq(ValueMatcher):
141 def matches(self, arg):
142 return arg != self.value
143
144
145 class Lt(ValueMatcher):
146 def matches(self, arg):
147 return arg < self.value
148
149
150 class Lte(ValueMatcher):
151 def matches(self, arg):
152 return arg <= self.value
153
154
155 class Gt(ValueMatcher):
156 def matches(self, arg):
157 return arg > self.value
158
159
160 class Gte(ValueMatcher):
161 def matches(self, arg):
162 return arg >= self.value
163
164
165 class And(Matcher):
166 def __init__(self, matchers):
167 self.matchers = [
168 matcher if isinstance(matcher, Matcher) else Eq(matcher)
169 for matcher in matchers]
170
171 def matches(self, arg):
172 return all(matcher.matches(arg) for matcher in self.matchers)
173
174 def __repr__(self):
175 return "<And: %s>" % self.matchers
176
177
178 class Or(Matcher):
179 def __init__(self, matchers):
180 self.matchers = [
181 matcher if isinstance(matcher, Matcher) else Eq(matcher)
182 for matcher in matchers]
183
184 def matches(self, arg):
185 return __builtins__['any'](
186 [matcher.matches(arg) for matcher in self.matchers]
187 )
188
189 def __repr__(self):
190 return "<Or: %s>" % self.matchers
191
192
193 class Not(Matcher):
194 def __init__(self, matcher):
195 self.matcher = matcher if isinstance(matcher, Matcher) else Eq(matcher)
196
197 def matches(self, arg):
198 return not self.matcher.matches(arg)
199
200 def __repr__(self):
201 return "<Not: %s>" % self.matcher
202
203
204 class ArgThat(Matcher):
205 def __init__(self, predicate):
206 self.predicate = predicate
207
208 def matches(self, arg):
209 return self.predicate(arg)
210
211 def __repr__(self):
212 return "<ArgThat>"
213
44214
45215 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
216 def __init__(self, sub):
217 self.sub = sub
218
219 def matches(self, arg):
220 if not hasattr(arg, 'find'):
221 return
222 return self.sub and len(self.sub) > 0 and arg.find(self.sub) > -1
223
224 def __repr__(self):
225 return "<Contains: '%s'>" % self.sub
226
227
228 class Matches(Matcher):
229 def __init__(self, regex, flags=0):
230 self.regex = re.compile(regex, flags)
231
232 def matches(self, arg):
233 if not isinstance(arg, str):
234 return
235 return self.regex.match(arg) is not None
236
237 def __repr__(self):
238 if self.regex.flags:
239 return "<Matches: %s flags=%d>" % (self.regex.pattern,
240 self.regex.flags)
241 else:
242 return "<Matches: %s>" % self.regex.pattern
243
244
245 class ArgumentCaptor(Matcher):
246 def __init__(self, matcher=None):
247 self.matcher = matcher or Any()
248 self.value = None
249
250 def matches(self, arg):
251 result = self.matcher.matches(arg)
252 if not result:
253 return
254 self.value = arg
255 return True
256
257 def __repr__(self):
258 return "<ArgumentCaptor: matcher=%s value=%s>" % (
259 repr(self.matcher), self.value,
260 )
261
262
58263 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
264 """Matches against type of argument (`isinstance`).
265
266 If you want to match *any* type, use either `ANY` or `ANY()`.
267
268 Examples::
269
270 when(mock).foo(any).thenReturn(1)
271 verify(mock).foo(any(int))
272
273 """
274 return Any(wanted_type)
275
276
277 ANY = any_ = any
278
279
280 def eq(value):
281 """Matches particular value (`==`)"""
282 return Eq(value)
283
284
285 def neq(value):
286 """Matches any but given value (`!=`)"""
287 return Neq(value)
288
289
290 def lt(value):
291 """Matches any value that is less than given value (`<`)"""
292 return Lt(value)
293
294
295 def lte(value):
296 """Matches any value that is less than or equal to given value (`<=`)"""
297 return Lte(value)
298
299
300 def gt(value):
301 """Matches any value that is greater than given value (`>`)"""
302 return Gt(value)
303
304
305 def gte(value):
306 """Matches any value that is greater than or equal to given value (`>=`)"""
307 return Gte(value)
308
309
310 def and_(*matchers):
311 """Matches if all given matchers match
312
313 Example::
314
315 when(mock).foo(and_(ANY(str), contains('foo')))
316
317 """
318 return And(matchers)
319
320
321 def or_(*matchers):
322 """Matches if any given matcher match
323
324 Example::
325
326 when(mock).foo(or_(ANY(int), ANY(float)))
327
328 """
329 return Or(matchers)
330
331
332 def not_(matcher):
333 """Matches if given matcher does not match
334
335 Example::
336
337 when(mock).foo(not_(ANY(str))).thenRaise(TypeError)
338
339 """
340 return Not(matcher)
341
342
343 def arg_that(predicate):
344 """Matches any argument for which predicate returns True
345
346 Example::
347
348 verify(mock).foo(arg_that(lambda arg: arg > 3 and arg < 7))
349
350 """
351 return ArgThat(predicate)
352
353
66354 def contains(sub):
67 return Contains(sub)
355 """Matches any string containing given substring
356
357 Example::
358
359 mock.foo([120, 121, 122, 123])
360 verify(mock).foo(contains(123))
361
362 """
363 return Contains(sub)
364
365
366 def matches(regex, flags=0):
367 """Matches any string that matches given regex"""
368 return Matches(regex, flags)
369
370
371 def captor(matcher=None):
372 """Returns argument captor that captures value for further assertions
373
374 Example::
375
376 arg_captor = captor(any(int))
377 when(mock).do_something(arg_captor)
378 mock.do_something(123)
379 assert arg_captor.value == 123
380
381 """
382 return ArgumentCaptor(matcher)
383
68384
69385 def times(count):
70 return count
386 return count
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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.
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
1921
2022 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()
23 """Registry for mocks
3724
38 mock_registry = MockRegistry()
25 Registers mock()s, ensures that we only have one mock() per mocked_obj, and
26 iterates over them to unstub each stubbed method.
27 """
28
29 def __init__(self):
30 self.mocks = _Dict()
31
32 def register(self, obj, mock):
33 self.mocks[obj] = mock
34
35 def mock_for(self, obj):
36 return self.mocks.get(obj, None)
37
38 def unstub(self, obj):
39 try:
40 mock = self.mocks.pop(obj)
41 except KeyError:
42 pass
43 else:
44 mock.unstub()
45
46 def unstub_all(self):
47 for mock in self.get_registered_mocks():
48 mock.unstub()
49 self.mocks.clear()
50
51 def get_registered_mocks(self):
52 return self.mocks.values()
53
54
55 # We have this dict like because we want non-hashable items in our registry.
56 # This is just enough to match the invoking code above. TBC
57 class _Dict(object):
58 def __init__(self):
59 self._store = []
60
61 def __setitem__(self, key, value):
62 self.remove(key)
63 self._store.append((key, value))
64
65 def remove(self, key):
66 self._store = [(k, v) for k, v in self._store if k != key]
67
68 def pop(self, key):
69 rv = self.get(key)
70 if rv is not None:
71 self.remove(key)
72 return rv
73 else:
74 raise KeyError()
75
76 def get(self, key, default=None):
77 for k, value in self._store:
78 if k == key:
79 return value
80 return default
81
82 def values(self):
83 return [v for k, v in self._store]
84
85 def clear(self):
86 self._store[:] = []
87
88
89 mock_registry = MockRegistry()
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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
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 collections import deque
2021 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)
22 import functools
23 import operator
24
25 from . import invocation
26 from . import signature
27 from . import utils
28 from .mock_registry import mock_registry
29
30
31 __all__ = ['mock']
32
33 __tracebackhide__ = operator.methodcaller(
34 "errisinstance",
35 invocation.InvocationError
36 )
37
38
39
40 class _Dummy(object):
41 # We spell out `__call__` here for convenience. All other magic methods
42 # must be configured before use, but we want `mock`s to be callable by
43 # default.
44 def __call__(self, *args, **kwargs):
45 return self.__getattr__('__call__')(*args, **kwargs)
46
47
48 def remembered_invocation_builder(mock, method_name, *args, **kwargs):
49 invoc = invocation.RememberedInvocation(mock, method_name)
50 return invoc(*args, **kwargs)
51
52
53 class Mock(object):
54 def __init__(self, mocked_obj, strict=True, spec=None):
55 self.mocked_obj = mocked_obj
56 self.strict = strict
57 self.spec = spec
58
59 self.invocations = deque()
60 self.stubbed_invocations = deque()
61
62 self.original_methods = {}
63 self._signatures_store = {}
64
65 def remember(self, invocation):
66 self.invocations.appendleft(invocation)
67
68 def finish_stubbing(self, stubbed_invocation):
69 self.stubbed_invocations.appendleft(stubbed_invocation)
70
71 def clear_invocations(self):
72 self.invocations = deque()
73
74 # STUBBING
75
76 def get_original_method(self, method_name):
77 if self.spec is None:
78 return None
79
80 try:
81 return self.spec.__dict__.get(method_name)
82 except AttributeError:
83 return getattr(self.spec, method_name, None)
84
85 def set_method(self, method_name, new_method):
86 setattr(self.mocked_obj, method_name, new_method)
87
88 def replace_method(self, method_name, original_method):
89
90 def new_mocked_method(*args, **kwargs):
91 # we throw away the first argument, if it's either self or cls
92 if (
93 inspect.ismethod(new_mocked_method)
94 or inspect.isclass(self.mocked_obj)
95 and not isinstance(new_mocked_method, staticmethod)
96 ):
97 args = args[1:]
98
99 return remembered_invocation_builder(
100 self, method_name, *args, **kwargs)
101
102 new_mocked_method.__name__ = method_name
103 if original_method:
104 new_mocked_method.__doc__ = original_method.__doc__
105 new_mocked_method.__wrapped__ = original_method
106 try:
107 new_mocked_method.__module__ = original_method.__module__
108 except AttributeError:
109 pass
110
111 if inspect.ismethod(original_method):
112 new_mocked_method = utils.newmethod(
113 new_mocked_method, self.mocked_obj
114 )
115
116 if isinstance(original_method, staticmethod):
117 new_mocked_method = staticmethod(new_mocked_method)
118 elif isinstance(original_method, classmethod):
119 new_mocked_method = classmethod(new_mocked_method)
120 elif (
121 inspect.isclass(self.mocked_obj)
122 and inspect.isclass(original_method) # TBC: Inner classes
123 ):
124 new_mocked_method = staticmethod(new_mocked_method)
125
126 self.set_method(method_name, new_mocked_method)
127
128 def stub(self, method_name):
129 try:
130 self.original_methods[method_name]
131 except KeyError:
132 original_method = self.get_original_method(method_name)
133 self.original_methods[method_name] = original_method
134
135 self.replace_method(method_name, original_method)
136
137 def forget_stubbed_invocation(self, invocation):
138 assert invocation in self.stubbed_invocations
139
140 if len(self.stubbed_invocations) == 1:
141 mock_registry.unstub(self.mocked_obj)
142 return
143
144 self.stubbed_invocations.remove(invocation)
145
146 if not any(
147 inv.method_name == invocation.method_name
148 for inv in self.stubbed_invocations
149 ):
150 original_method = self.original_methods.pop(invocation.method_name)
151 self.restore_method(invocation.method_name, original_method)
152
153 def restore_method(self, method_name, original_method):
154 # If original_method is None, we *added* it to mocked_obj, so we
155 # must delete it here.
156 # If we mocked an instance, our mocked function will actually hide
157 # the one on its class, so we delete as well.
158 if (
159 not original_method
160 or not inspect.isclass(self.mocked_obj)
161 and inspect.ismethod(original_method)
162 ):
163 delattr(self.mocked_obj, method_name)
164 else:
165 self.set_method(method_name, original_method)
166
167 def unstub(self):
168 while self.original_methods:
169 method_name, original_method = self.original_methods.popitem()
170 self.restore_method(method_name, original_method)
171
172 # SPECCING
173
174 def has_method(self, method_name):
175 if self.spec is None:
176 return True
177
178 return hasattr(self.spec, method_name)
179
180 def get_signature(self, method_name):
181 if self.spec is None:
182 return None
183
184 try:
185 return self._signatures_store[method_name]
186 except KeyError:
187 sig = signature.get_signature(self.spec, method_name)
188 self._signatures_store[method_name] = sig
189 return sig
190
191
192 class _OMITTED(object):
193 def __repr__(self):
194 return 'OMITTED'
195
196
197 OMITTED = _OMITTED()
198
199 def mock(config_or_spec=None, spec=None, strict=OMITTED):
200 """Create 'empty' objects ('Mocks').
201
202 Will create an empty unconfigured object, that you can pass
203 around. All interactions (method calls) will be recorded and can be
204 verified using :func:`verify` et.al.
205
206 A plain `mock()` will be not `strict`, and thus all methods regardless
207 of the arguments will return ``None``.
208
209 .. note:: Technically all attributes will return an internal interface.
210 Because of that a simple ``if mock().foo:`` will surprisingly pass.
211
212 If you set strict to ``True``: ``mock(strict=True)`` all unexpected
213 interactions will raise an error instead.
214
215 You configure a mock using :func:`when`, :func:`when2` or :func:`expect`.
216 You can also very conveniently just pass in a dict here::
217
218 response = mock({'text': 'ok', 'raise_for_status': lambda: None})
219
220 You can also create an empty Mock which is specced against a given
221 `spec`: ``mock(requests.Response)``. These mock are by default strict,
222 thus they raise if you want to stub a method, the spec does not implement.
223 Mockito will also match the function signature.
224
225 You can pre-configure a specced mock as well::
226
227 response = mock({'json': lambda: {'status': 'Ok'}},
228 spec=requests.Response)
229
230 Mocks are by default callable. Configure the callable behavior using
231 `when`::
232
233 dummy = mock()
234 when(dummy).__call_(1).thenReturn(2)
235
236 All other magic methods must be configured this way or they will raise an
237 AttributeError.
238
239
240 See :func:`verify` to verify your interactions after usage.
241
242 """
243
244 if type(config_or_spec) is dict:
245 config = config_or_spec
246 else:
247 config = {}
248 spec = config_or_spec
249
250 if strict is OMITTED:
251 strict = False if spec is None else True
252
253
254 class Dummy(_Dummy):
255 if spec:
256 __class__ = spec # make isinstance work
257
258 def __getattr__(self, method_name):
259 if strict:
260 __tracebackhide__ = operator.methodcaller(
261 "errisinstance", AttributeError
262 )
263
264 raise AttributeError(
265 "'Dummy' has no attribute %r configured" % method_name)
266 return functools.partial(
267 remembered_invocation_builder, theMock, method_name)
268
269 def __repr__(self):
270 name = 'Dummy'
271 if spec:
272 name += spec.__name__
273 return "<%s id=%s>" % (name, id(self))
274
275
276 # That's a tricky one: The object we will return is an *instance* of our
277 # Dummy class, but the mock we register will point and patch the class.
278 # T.i. so that magic methods (`__call__` etc.) can be configured.
279 obj = Dummy()
280 theMock = Mock(Dummy, strict=strict, spec=spec)
281
282 for n, v in config.items():
283 if inspect.isfunction(v):
284 invocation.StubbedInvocation(theMock, n)(Ellipsis).thenAnswer(v)
285 else:
286 setattr(Dummy, n, v)
287
288 mock_registry.register(obj, theMock)
289 return obj
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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
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 operator
21
22 from . import invocation
23 from . import verification
24
25 from .utils import get_obj, get_obj_attr_tuple
26 from .mocking import Mock
27 from .mock_registry import mock_registry
28 from .verification import VerificationError
2429
2530
2631 class ArgumentError(Exception):
27 pass
32 pass
33
34
35 __tracebackhide__ = operator.methodcaller(
36 "errisinstance", (ArgumentError, VerificationError)
37 )
38
2839
2940 def _multiple_arguments_in_use(*args):
30 return len(filter(lambda x: x, args)) > 1
41 return len([x for x in args if x]) > 1
42
3143
3244 def _invalid_argument(value):
33 return (value is not None and value < 1) or value == 0
45 return (value is not None and value < 1) or value == 0
46
3447
3548 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:
49 if between is not None:
50 try:
51 start, end = between
52 except Exception:
53 return True
54
55 if start > end or start < 0:
56 return True
57 return False
58
59 def _get_wanted_verification(
60 times=None, atleast=None, atmost=None, between=None):
61 if times is not None and times < 0:
62 raise ArgumentError("'times' argument has invalid value.\n"
63 "It should be at least 0. You wanted to set it to:"
64 " %i" % times)
65 if _multiple_arguments_in_use(atleast, atmost, between):
66 raise ArgumentError(
67 "You can set only one of the arguments: 'atleast', "
68 "'atmost' or 'between'.")
69 if _invalid_argument(atleast):
70 raise ArgumentError("'atleast' argument has invalid value.\n"
71 "It should be at least 1. You wanted to set it "
72 "to: %i" % atleast)
73 if _invalid_argument(atmost):
74 raise ArgumentError("'atmost' argument has invalid value.\n"
75 "It should be at least 1. You wanted to set it "
76 "to: %i" % atmost)
77 if _invalid_between(between):
78 raise ArgumentError(
79 """'between' argument has invalid value.
80 It should consist of positive values with second number not greater
81 than first e.g. (1, 4) or (0, 3) or (2, 2).
82 You wanted to set it to: %s""" % (between,))
83
84 if atleast:
85 return verification.AtLeast(atleast)
86 elif atmost:
87 return verification.AtMost(atmost)
88 elif between:
89 return verification.Between(*between)
90 elif times is not None:
91 return verification.Times(times)
92
93 def _get_mock(obj, strict=True):
8494 theMock = mock_registry.mock_for(obj)
8595 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)
96 theMock = Mock(obj, strict=strict, spec=obj)
97 mock_registry.register(obj, theMock)
98 return theMock
99
100 def _get_mock_or_raise(obj):
101 theMock = mock_registry.mock_for(obj)
102 if theMock is None:
103 raise ArgumentError("obj '%s' is not registered" % obj)
104 return theMock
105
106 def verify(obj, times=1, atleast=None, atmost=None, between=None,
107 inorder=False):
108 """Central interface to verify interactions.
109
110 `verify` uses a fluent interface::
111
112 verify(<obj>, times=2).<method_name>(<args>)
113
114 `args` can be as concrete as necessary. Often a catch-all is enough,
115 especially if you're working with strict mocks, bc they throw at call
116 time on unwanted, unconfigured arguments::
117
118 from mockito import ANY, ARGS, KWARGS
119 when(manager).add_tasks(1, 2, 3)
120 ...
121 # no need to duplicate the specification; every other argument pattern
122 # would have raised anyway.
123 verify(manager).add_tasks(1, 2, 3) # duplicates `when`call
124 verify(manager).add_tasks(*ARGS)
125 verify(manager).add_tasks(...) # Py3
126 verify(manager).add_tasks(Ellipsis) # Py2
127
128 """
129
130 if isinstance(obj, str):
131 obj = get_obj(obj)
132
133 verification_fn = _get_wanted_verification(
134 times=times, atleast=atleast, atmost=atmost, between=between)
135 if inorder:
136 verification_fn = verification.InOrder(verification_fn)
137
138 theMock = _get_mock_or_raise(obj)
139
140 class Verify(object):
141 def __getattr__(self, method_name):
142 return invocation.VerifiableInvocation(
143 theMock, method_name, verification_fn)
144
145 return Verify()
146
147
148 class _OMITTED(object):
149 def __repr__(self):
150 return 'OMITTED'
151
152
153 OMITTED = _OMITTED()
154
155
156 def when(obj, strict=True):
157 """Central interface to stub functions on a given `obj`
158
159 `obj` should be a module, a class or an instance of a class; it can be
160 a Dummy you created with :func:`mock`. ``when`` exposes a fluent interface
161 where you configure a stub in three steps::
162
163 when(<obj>).<method_name>(<args>).thenReturn(<value>)
164
165 Compared to simple *patching*, stubbing in mockito requires you to specify
166 conrete `args` for which the stub will answer with a concrete `<value>`.
167 All invocations that do not match this specific call signature will be
168 rejected. They usually throw at call time.
169
170 Stubbing in mockito's sense thus means not only to get rid of unwanted
171 side effects, but effectively to turn function calls into constants.
172
173 E.g.::
174
175 # Given ``dog`` is an instance of a ``Dog``
176 when(dog).bark('Grrr').thenReturn('Wuff')
177 when(dog).bark('Miau').thenRaise(TypeError())
178
179 # With this configuration set up:
180 assert dog.bark('Grrr') == 'Wuff'
181 dog.bark('Miau') # will throw TypeError
182 dog.bark('Wuff') # will throw unwanted interaction
183
184 Stubbing can effectively be used as monkeypatching; usage shown with
185 the `with` context managing::
186
187 with when(os.path).exists('/foo').thenReturn(True):
188 ...
189
190 Most of the time verifying your interactions is not necessary, because
191 your code under tests implicitly verifies the return value by evaluating
192 it. See :func:`verify` if you need to, see also :func:`expect` to setup
193 expected call counts up front.
194
195 If your function is pure side effect and does not return something, you
196 can omit the specific answer. The default then is `None`::
197
198 when(manager).do_work()
199
200 `when` verifies the method name, the expected argument signature, and the
201 actual, factual arguments your code under test uses against the original
202 object and its function so its easier to spot changing interfaces.
203
204 Sometimes it's tedious to spell out all arguments::
205
206 from mockito import ANY, ARGS, KWARGS
207 when(requests).get('http://example.com/', **KWARGS).thenReturn(...)
208 when(os.path).exists(ANY)
209 when(os.path).exists(ANY(str))
210
211 .. note:: You must :func:`unstub` after stubbing, or use `with`
212 statement.
213
214 Set ``strict=False`` to bypass the function signature checks.
215
216 See related :func:`when2` which has a more pythonic interface.
217
218 """
219
220 if isinstance(obj, str):
221 obj = get_obj(obj)
222
223 theMock = _get_mock(obj, strict=strict)
224
225 class When(object):
226 def __getattr__(self, method_name):
227 return invocation.StubbedInvocation(
228 theMock, method_name, strict=strict)
229
230 return When()
231
232
233 def when2(fn, *args, **kwargs):
234 """Stub a function call with the given arguments
235
236 Exposes a more pythonic interface than :func:`when`. See :func:`when` for
237 more documentation.
238
239 Returns `AnswerSelector` interface which exposes `thenReturn`,
240 `thenRaise`, and `thenAnswer` as usual. Always `strict`.
241
242 Usage::
243
244 # Given `dog` is an instance of a `Dog`
245 when2(dog.bark, 'Miau').thenReturn('Wuff')
246
247 .. note:: You must :func:`unstub` after stubbing, or use `with`
248 statement.
249
250 """
251 obj, name = get_obj_attr_tuple(fn)
252 theMock = _get_mock(obj, strict=True)
253 return invocation.StubbedInvocation(theMock, name)(*args, **kwargs)
254
255
256 def patch(fn, attr_or_replacement, replacement=None):
257 """Patch/Replace a function.
258
259 This is really like monkeypatching, but *note* that all interactions
260 will be recorded and can be verified. That is, using `patch` you stay in
261 the domain of mockito.
262
263 Two ways to call this. Either::
264
265 patch(os.path.exists, lambda str: True) # two arguments
266 # OR
267 patch(os.path, 'exists', lambda str: True) # three arguments
268
269 If called with three arguments, the mode is *not* strict to allow *adding*
270 methods. If called with two arguments, mode is always `strict`.
271
272 .. note:: You must :func:`unstub` after stubbing, or use `with`
273 statement.
274
275 """
276 if replacement is None:
277 replacement = attr_or_replacement
278 return when2(fn, Ellipsis).thenAnswer(replacement)
279 else:
280 obj, name = fn, attr_or_replacement
281 theMock = _get_mock(obj, strict=True)
282 return invocation.StubbedInvocation(
283 theMock, name, strict=False)(Ellipsis).thenAnswer(replacement)
284
285
286
287 def expect(obj, strict=None,
288 times=None, atleast=None, atmost=None, between=None):
289 """Stub a function call, and set up an expected call count.
290
291 Usage::
292
293 # Given `dog` is an instance of a `Dog`
294 expect(dog, times=1).bark('Wuff').thenReturn('Miau')
295 dog.bark('Wuff')
296 dog.bark('Wuff') # will throw at call time: too many invocations
297
298 # maybe if you need to ensure that `dog.bark()` was called at all
299 verifyNoUnwantedInteractions()
300
301 .. note:: You must :func:`unstub` after stubbing, or use `with`
302 statement.
303
304 See :func:`when`, :func:`when2`, :func:`verifyNoUnwantedInteractions`
305
306 """
307 if strict is None:
308 strict = True
309 theMock = _get_mock(obj, strict=strict)
310
311 verification_fn = _get_wanted_verification(
312 times=times, atleast=atleast, atmost=atmost, between=between)
313
314 class Expect(object):
315 def __getattr__(self, method_name):
316 return invocation.StubbedInvocation(
317 theMock, method_name, verification=verification_fn,
318 strict=strict)
319
320 return Expect()
321
322
323
324 def unstub(*objs):
325 """Unstubs all stubbed methods and functions
326
327 If you don't pass in any argument, *all* registered mocks and
328 patched modules, classes etc. will be unstubbed.
329
330 Note that additionally, the underlying registry will be cleaned.
331 After an `unstub` you can't :func:`verify` anymore because all
332 interactions will be forgotten.
333 """
334
335 if objs:
336 for obj in objs:
337 mock_registry.unstub(obj)
338 else:
339 mock_registry.unstub_all()
340
341
342 def forget_invocations(*objs):
343 """Forget all invocations of given objs.
344
345 If you already *call* mocks during your setup routine, you can now call
346 ``forget_invocations`` at the end of your setup, and have a clean
347 'recording' for your actual test code. T.i. you don't have
348 to count the invocations from your setup code anymore when using
349 :func:`verify` afterwards.
350 """
351 for obj in objs:
352 theMock = _get_mock_or_raise(obj)
353 theMock.clear_invocations()
354
355
356 def verifyNoMoreInteractions(*objs):
357 verifyNoUnwantedInteractions(*objs)
358
359 for obj in objs:
360 theMock = _get_mock_or_raise(obj)
361
362 for i in theMock.invocations:
363 if not i.verified:
364 raise VerificationError("\nUnwanted interaction: %s" % i)
365
366
367 def verifyZeroInteractions(*objs):
368 """Verify that no methods have been called on given objs.
369
370 Note that strict mocks usually throw early on unexpected, unstubbed
371 invocations. Partial mocks ('monkeypatched' objects or modules) do not
372 support this functionality at all, bc only for the stubbed invocations
373 the actual usage gets recorded. So this function is of limited use,
374 nowadays.
375
376 """
377 for obj in objs:
378 theMock = _get_mock_or_raise(obj)
379
380 if len(theMock.invocations) > 0:
381 raise VerificationError(
382 "\nUnwanted interaction: %s" % theMock.invocations[0])
383
384
385
386 def verifyNoUnwantedInteractions(*objs):
387 """Verifies that expectations set via `expect` are met
388
389 E.g.::
390
391 expect(os.path, times=1).exists(...).thenReturn(True)
392 os.path('/foo')
393 verifyNoUnwantedInteractions(os.path) # ok, called once
394
395 If you leave out the argument *all* registered objects will
396 be checked.
397
398 .. note:: **DANGERZONE**: If you did not :func:`unstub` correctly,
399 it is possible that old registered mocks, from other tests
400 leak.
401
402 See related :func:`expect`
403 """
404
405 if objs:
406 theMocks = map(_get_mock_or_raise, objs)
407 else:
408 theMocks = mock_registry.get_registered_mocks()
409
410 for mock in theMocks:
411 for i in mock.stubbed_invocations:
412 i.verify()
413
414 def verifyStubbedInvocationsAreUsed(*objs):
415 """Ensure stubs are actually used.
416
417 This functions just ensures that stubbed methods are actually used. Its
418 purpose is to detect interface changes after refactorings. It is meant
419 to be invoked usually without arguments just before :func:`unstub`.
420
421 """
422 if objs:
423 theMocks = map(_get_mock_or_raise, objs)
424 else:
425 theMocks = mock_registry.get_registered_mocks()
426
427
428 for mock in theMocks:
429 for i in mock.stubbed_invocations:
430 if not i.allow_zero_invocations and i.used < len(i.answers):
431 raise VerificationError("\nUnused stub: %s" % i)
432
0
1 from . import matchers
2 from .utils import contains_strict
3
4 import functools
5 import inspect
6 import sys
7 import types
8
9 try:
10 from inspect import signature, Parameter
11 except ImportError:
12 from funcsigs import signature, Parameter
13
14
15 PY3 = sys.version_info >= (3,)
16
17
18 def get_signature(obj, method_name):
19 method = getattr(obj, method_name)
20
21 # Eat self for unbound methods bc signature doesn't do it
22 if PY3:
23 if (
24 inspect.isclass(obj)
25 and not inspect.ismethod(method)
26 and not isinstance(obj.__dict__.get(method_name), staticmethod)
27 ):
28 method = functools.partial(method, None)
29 else:
30 if (
31 isinstance(method, types.UnboundMethodType)
32 and method.__self__ is None
33 ):
34 method = functools.partial(method, None)
35
36 try:
37 return signature(method)
38 except Exception:
39 return None
40
41
42 def match_signature(sig, args, kwargs):
43 sig.bind(*args, **kwargs)
44 return sig
45
46
47 def match_signature_allowing_placeholders(sig, args, kwargs): # noqa: C901
48 # Let's face it. If this doesn't work out, we have to do it the hard
49 # way and reimplement something like `sig.bind` with our specific
50 # need for `...`, `*args`, and `**kwargs` support.
51
52 if contains_strict(args, Ellipsis):
53 # Invariant: Ellipsis as the sole argument should just pass, regardless
54 # if it actually can consume an arg or the function does not take any
55 # arguments at all
56 if len(args) == 1:
57 return
58
59 has_kwargs = has_var_keyword(sig)
60 # Ellipsis is always the last arg in args; it matches all keyword
61 # arguments as well. So the strategy here is to strip off all
62 # the keyword arguments from the signature, and do a partial
63 # bind with the rest.
64 params = [p for n, p in sig.parameters.items()
65 if p.kind not in (Parameter.KEYWORD_ONLY,
66 Parameter.VAR_KEYWORD)]
67 sig = sig.replace(parameters=params)
68 # Ellipsis should fill at least one argument. We strip it off if
69 # it can stand for a `kwargs` argument.
70 sig.bind_partial(*(args[:-1] if has_kwargs else args))
71 else:
72 # `*args` should at least match one arg (t.i. not `*[]`), so we
73 # keep it here. The value and its type is irrelevant in python.
74 args_provided = contains_strict(args, matchers.ARGS_SENTINEL)
75
76 # If we find the `**kwargs` sentinel we must remove it, bc its
77 # name cannot be matched against the sig.
78 kwargs_provided = matchers.KWARGS_SENTINEL in kwargs
79 if kwargs_provided:
80 kwargs = kwargs.copy()
81 kwargs.pop(matchers.KWARGS_SENTINEL)
82
83
84 if args_provided or kwargs_provided:
85 try:
86 sig.bind(*args, **kwargs)
87 except TypeError as e:
88 error = str(e)
89 if 'too many positional arguments' in error:
90 raise TypeError('no argument for *args left')
91 if 'multiple values for argument' in error:
92 raise
93 if 'too many keyword arguments' in error: # PY<3.5
94 raise
95 if 'got an unexpected keyword argument' in error: # PY>3.5
96 raise
97
98 else:
99 if kwargs_provided and not has_var_keyword(sig):
100 pos_args = positional_arguments(sig)
101 len_args = len(args) - int(args_provided)
102 len_kwargs = len(kwargs)
103 provided_args = len_args + len_kwargs
104 # Substitute at least one argument for the `**kwargs`,
105 # the user provided; t.i. do not allow kwargs to
106 # satisfy an empty `{}`.
107 if provided_args + 1 > pos_args:
108 raise TypeError(
109 'no keyword argument for **kwargs left')
110
111 else:
112 # Without Ellipsis and the other stuff this would really be
113 # straight forward.
114 sig.bind(*args, **kwargs)
115
116 return sig
117
118
119 def positional_arguments(sig):
120 return len([p for n, p in sig.parameters.items()
121 if p.kind in (Parameter.POSITIONAL_ONLY,
122 Parameter.POSITIONAL_OR_KEYWORD)])
123
124 def has_var_keyword(sig):
125 return any(p for n, p in sig.parameters.items()
126 if p.kind is Parameter.VAR_KEYWORD)
127
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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.
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.
1919
2020 '''Spying on real objects.'''
2121
22 from invocation import RememberedProxyInvocation, VerifiableInvocation
23 from mocking import TestDouble
22 import inspect
2423
25 __author__ = "Serhiy Oplakanets <[email protected]>"
24 from .mockito import when2
25 from .invocation import RememberedProxyInvocation
26 from .mocking import Mock, _Dummy, mock_registry
27 from .utils import get_obj
2628
2729 __all__ = ['spy']
2830
29 def spy(original_object):
30 return Spy(original_object)
3131
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)
32 def spy(object):
33 """Spy an object.
34
35 Spying means that all functions will behave as before, so they will
36 be side effects, but the interactions can be verified afterwards.
37
38 Returns Dummy-like, almost empty object as proxy to `object`.
39
40 The *returned* object must be injected and used by the code under test;
41 after that all interactions can be verified as usual.
42 T.i. the original object **will not be patched**, and has no further
43 knowledge as before.
44
45 E.g.::
46
47 import time
48 time = spy(time)
49 # inject time
50 do_work(..., time)
51 verify(time).time()
52
53 """
54 if inspect.isclass(object) or inspect.ismodule(object):
55 class_ = None
4356 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
57 class_ = object.__class__
58
59 class Spy(_Dummy):
60 if class_:
61 __class__ = class_
62
63 def __getattr__(self, method_name):
64 return RememberedProxyInvocation(theMock, method_name)
65
66 def __repr__(self):
67 name = 'Spied'
68 if class_:
69 name += class_.__name__
70 return "<%s id=%s>" % (name, id(self))
71
72
73 obj = Spy()
74 theMock = Mock(obj, strict=True, spec=object)
75
76 mock_registry.register(obj, theMock)
77 return obj
78
79
80 def spy2(fn): # type: (...) -> None
81 """Spy usage of given `fn`.
82
83 Patches the module, class or object `fn` lives in, so that all
84 interactions can be recorded; otherwise executes `fn` as before, so
85 that all side effects happen as before.
86
87 E.g.::
88
89 import time
90 spy(time.time)
91 do_work(...) # nothing injected, uses global patched `time` module
92 verify(time).time()
93
94 Note that builtins often cannot be patched because they're read-only.
95
96
97 """
98 if isinstance(fn, str):
99 answer = get_obj(fn)
100 else:
101 answer = fn
102
103 when2(fn, Ellipsis).thenAnswer(answer)
104
0
1 import importlib
2 import inspect
3 import sys
4 import types
5 import re
6
7
8 PY3 = sys.version_info >= (3,)
9
10
11 def contains_strict(seq, element):
12 return any(item is element for item in seq)
13
14
15 def newmethod(fn, obj):
16 if PY3:
17 return types.MethodType(fn, obj)
18 else:
19 return types.MethodType(fn, obj, obj.__class__)
20
21
22 def get_function_host(fn):
23 """Destructure a given function into its host and its name.
24
25 The 'host' of a function is a module, for methods it is usually its
26 instance or its class. This is safe only for methods, for module wide,
27 globally declared names it must be considered experimental.
28
29 For all reasonable fn: ``getattr(*get_function_host(fn)) == fn``
30
31 Returns tuple (host, fn-name)
32 Otherwise should raise TypeError
33 """
34
35 obj = None
36 try:
37 name = fn.__name__
38 obj = fn.__self__
39 except AttributeError:
40 pass
41
42 if obj is None:
43 # Due to how python imports work, everything that is global on a module
44 # level must be regarded as not safe here. For now, we go for the extra
45 # mile, TBC, because just specifying `os.path.exists` would be 'cool'.
46 #
47 # TLDR;:
48 # E.g. `inspect.getmodule(os.path.exists)` returns `genericpath` bc
49 # that's where `exists` is defined and comes from. But from the point
50 # of view of the user `exists` always comes and is used from `os.path`
51 # which points e.g. to `ntpath`. We thus must patch `ntpath`.
52 # But that's the same for most imports::
53 #
54 # # b.py
55 # from a import foo
56 #
57 # Now asking `getmodule(b.foo)` it tells you `a`, but we access and use
58 # `b.foo` and we therefore must patch `b`.
59
60 obj, name = find_invoking_frame_and_try_parse()
61 # safety check!
62 assert getattr(obj, name) == fn
63
64
65 return obj, name
66
67
68 FIND_ID = re.compile(r'.*\s*.*(?:when2|patch|spy2)\(\s*(.+?)[,\)]', re.M)
69
70
71 def find_invoking_frame_and_try_parse():
72 # Actually we just want the first frame in user land; we're open for
73 # refactorings here and don't yet decide on which frame exactly we hit
74 # that user land.
75 stack = inspect.stack(3)[2:10]
76 for frame_info in stack:
77 # Within `patch` and `spy2` we delegate to `when2` but that's not
78 # user land code
79 if frame_info[3] in ('patch', 'spy2'):
80 continue
81
82 source = ''.join(frame_info[4])
83 m = FIND_ID.match(source)
84 if m:
85 # id should be something like `os.path.exists` etc.
86 id = m.group(1)
87 parts = id.split('.')
88 if len(parts) < 2:
89 raise TypeError("can't guess origin of '%s'" % id)
90
91 frame = frame_info[0]
92 vars = frame.f_globals.copy()
93 vars.update(frame.f_locals)
94
95 # Now that's a simple reduce; we get the initial value from the
96 # locally available `vars`, and then reduce the middle parts via
97 # `getattr`. The last path component gets not resolved, but is
98 # returned as plain string value.
99 obj = vars.get(parts[0])
100 for part in parts[1:-1]:
101 obj = getattr(obj, part)
102 return obj, parts[-1]
103
104 raise TypeError('could not destructure first argument')
105
106 def get_obj(path):
107 """Return obj for given dotted path.
108
109 Typical inputs for `path` are 'os' or 'os.path' in which case you get a
110 module; or 'os.path.exists' in which case you get a function from that
111 module.
112
113 Just returns the given input in case it is not a str.
114
115 Note: Relative imports not supported.
116 Raises ImportError or AttributeError as appropriate.
117
118 """
119 # Since we usually pass in mocks here; duck typing is not appropriate
120 # (mocks respond to every attribute).
121 if not isinstance(path, str):
122 return path
123
124 if path.startswith('.'):
125 raise TypeError('relative imports are not supported')
126
127 parts = path.split('.')
128 head, tail = parts[0], parts[1:]
129
130 obj = importlib.import_module(head)
131
132 # Normally a simple reduce, but we go the extra mile
133 # for good exception messages.
134 for i, name in enumerate(tail):
135 try:
136 obj = getattr(obj, name)
137 except AttributeError:
138 # Note the [:i] instead of [:i+1], so we get the path just
139 # *before* the AttributeError, t.i. the part of it that went ok.
140 module = '.'.join([head] + tail[:i])
141 try:
142 importlib.import_module(module)
143 except ImportError:
144 raise AttributeError(
145 "object '%s' has no attribute '%s'" % (module, name))
146 else:
147 raise AttributeError(
148 "module '%s' has no attribute '%s'" % (module, name))
149 return obj
150
151 def get_obj_attr_tuple(path):
152 """Split path into (obj, attribute) tuple.
153
154 Given `path` is 'os.path.exists' will thus return `(os.path, 'exists')`
155
156 If path is not a str, delegates to `get_function_host(path)`
157
158 """
159 if not isinstance(path, str):
160 return get_function_host(path)
161
162 if path.startswith('.'):
163 raise TypeError('relative imports are not supported')
164
165 try:
166 leading, end = path.rsplit('.', 1)
167 except ValueError:
168 raise TypeError('path must have dots')
169
170 return get_obj(leading), end
171
172
173
174
175
0 # Copyright (c) 2008-2013 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
0 # Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste
11 #
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:
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:
88 #
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
9 # The above copyright notice and this permission notice shall be included in
10 # all copies or substantial portions of the Software.
1111 #
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.
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 operator
1921
2022 __all__ = ['never', 'VerificationError']
2123
2224 class VerificationError(AssertionError):
23 '''Indicates error during verification of invocations.
24
25 Raised if verification fails. Error message contains the cause.
26 '''
27 pass
25 '''Indicates error during verification of invocations.
26
27 Raised if verification fails. Error message contains the cause.
28 '''
29 pass
30
31
32 __tracebackhide__ = operator.methodcaller("errisinstance", VerificationError)
33
2834
2935 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
36 def __init__(self, wanted_count):
37 self.wanted_count = wanted_count
38
39 def verify(self, invocation, actual_count):
40 if actual_count < self.wanted_count:
41 raise VerificationError("\nWanted at least: %i, actual times: %i"
42 % (self.wanted_count, actual_count))
43
44 def __repr__(self):
45 return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count)
46
3747 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))
48 def __init__(self, wanted_count):
49 self.wanted_count = wanted_count
50
51 def verify(self, invocation, actual_count):
52 if actual_count > self.wanted_count:
53 raise VerificationError("\nWanted at most: %i, actual times: %i"
54 % (self.wanted_count, actual_count))
55
56 def __repr__(self):
57 return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count)
4458
4559 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
60 def __init__(self, wanted_from, wanted_to):
61 self.wanted_from = wanted_from
62 self.wanted_to = wanted_to
63
64 def verify(self, invocation, actual_count):
65 if actual_count < self.wanted_from or actual_count > self.wanted_to:
66 raise VerificationError(
67 "\nWanted between: [%i, %i], actual times: %i"
68 % (self.wanted_from, self.wanted_to, actual_count))
69
70 def __repr__(self):
71 return "<%s [%s, %s]>" % (
72 type(self).__name__, self.wanted_from, self.wanted_to)
73
5474 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
75 def __init__(self, wanted_count):
76 self.wanted_count = wanted_count
77
78 def verify(self, invocation, actual_count):
79 if actual_count == self.wanted_count:
80 return
81
82 if actual_count == 0:
83 invocations = (
84 [
85 invoc
86 for invoc in invocation.mock.invocations
87 if invoc.method_name == invocation.method_name
88 ]
89 or invocation.mock.invocations
90 or ['Nothing']
91 )
92 raise VerificationError(
93 """
94 Wanted but not invoked:
95
96 %s
97
98 Instead got:
99
100 %s
101
102 """
103 % (
104 invocation,
105 "\n ".join(
106 str(invoc) for invoc in reversed(invocations)
107 )
108 )
109 )
110 else:
111 if self.wanted_count == 0:
112 raise VerificationError(
113 "\nUnwanted invocation of %s, times: %i"
114 % (invocation, actual_count))
115 else:
116 raise VerificationError("\nWanted times: %i, actual times: %i"
117 % (self.wanted_count, actual_count))
118
119 def __repr__(self):
120 return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count)
121
69122 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.
123 '''Verifies invocations in order.
124
125 Verifies if invocation was in expected order, and if yes -- degrades to
126 original Verifier (AtLeast, Times, Between, ...).
79127 '''
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
128
129 def __init__(self, original_verification):
130 '''
131
132 @param original_verification: Original verifiaction to degrade to if
133 order of invocation was ok.
134 '''
135 self.original_verification = original_verification
136
137 def verify(self, wanted_invocation, count):
138 for invocation in reversed(wanted_invocation.mock.invocations):
139 if not invocation.verified_inorder:
140 if not wanted_invocation.matches(invocation):
141 raise VerificationError(
142 '\nWanted %s to be invoked,'
143 '\ngot %s instead.' %
144 (wanted_invocation, invocation))
145 invocation.verified_inorder = True
146 break
147 # proceed with original verification
148 self.original_verification.verify(wanted_invocation, count)
149
150
92151 never = 0
+0
-16
mockito.egg-info/PKG-INFO less more
0 Metadata-Version: 1.0
1 Name: mockito
2 Version: 0.5.2
3 Summary: Spying framework
4 Home-page: http://code.google.com/p/mockito-python
5 Author: Justin Hopper
6 Author-email: [email protected]
7 License: MIT
8 Download-URL: http://code.google.com/p/mockito-python/downloads/list
9 Description: Mockito is a spying framework based on Java library with the same name.
10 Platform: UNKNOWN
11 Classifier: Development Status :: 4 - Beta
12 Classifier: Intended Audience :: Developers
13 Classifier: License :: OSI Approved :: MIT License
14 Classifier: Topic :: Software Development :: Testing
15 Classifier: Programming Language :: Python :: 3
+0
-36
mockito.egg-info/SOURCES.txt less more
0 AUTHORS
1 LICENSE
2 MANIFEST.in
3 README.rst
4 distribute_setup.py
5 setup.cfg
6 setup.py
7 mockito/__init__.py
8 mockito/inorder.py
9 mockito/invocation.py
10 mockito/matchers.py
11 mockito/mock_registry.py
12 mockito/mocking.py
13 mockito/mockito.py
14 mockito/spying.py
15 mockito/verification.py
16 mockito.egg-info/PKG-INFO
17 mockito.egg-info/SOURCES.txt
18 mockito.egg-info/dependency_links.txt
19 mockito.egg-info/top_level.txt
20 mockito_test/__init__.py
21 mockito_test/classmethods_test.py
22 mockito_test/demo_test.py
23 mockito_test/instancemethods_test.py
24 mockito_test/matchers_test.py
25 mockito_test/mockingexacttypes_test.py
26 mockito_test/modulefunctions_test.py
27 mockito_test/spying_test.py
28 mockito_test/staticmethods_test.py
29 mockito_test/stubbing_test.py
30 mockito_test/test_base.py
31 mockito_test/verification_errors_test.py
32 mockito_test/verifications_test.py
33 mockito_util/__init__.py
34 mockito_util/test.py
35 mockito_util/write_readme.py
+0
-1
mockito.egg-info/dependency_links.txt less more
0
+0
-4
mockito.egg-info/top_level.txt less more
0 mockito_util
1 distribute_setup
2 mockito
3 mockito_test
+0
-19
mockito_test/__init__.py less more
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
-104
mockito_test/classmethods_test.py less more
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
-56
mockito_test/demo_test.py less more
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
-94
mockito_test/instancemethods_test.py less more
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
-49
mockito_test/matchers_test.py less more
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
-48
mockito_test/mockingexacttypes_test.py less more
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
-94
mockito_test/modulefunctions_test.py less more
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
-64
mockito_test/spying_test.py less more
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
-154
mockito_test/staticmethods_test.py less more
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
-255
mockito_test/stubbing_test.py less more
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
-39
mockito_test/test_base.py less more
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
-94
mockito_test/verification_errors_test.py less more
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
-275
mockito_test/verifications_test.py less more
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
-19
mockito_util/__init__.py less more
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
-47
mockito_util/test.py less more
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
-42
mockito_util/write_readme.py less more
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
-9
setup.cfg less more
0 [nosetests]
1 where = mockito_test
2 detailed-errors = 1
3
4 [egg_info]
5 tag_build =
6 tag_date = 0
7 tag_svn_revision = 0
8
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
0 from setuptools import setup
101 import sys
112
12 extra = {}
13 if sys.version_info >= (3,):
14 extra['use_2to3'] = True
3 import re
4 import ast
5
6
7 _version_re = re.compile(r'__version__\s+=\s+(.*)')
8
9 with open('mockito/__init__.py', 'rb') as f:
10 version = str(ast.literal_eval(_version_re.search(
11 f.read().decode('utf-8')).group(1)))
12
13
14 install_requires = ['funcsigs'] if sys.version_info < (3,) else []
1515
1616 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]',
17 version=version,
18 packages=['mockito'],
19 url='https://github.com/kaste/mockito-python',
20 maintainer='herr.kaste',
21 maintainer_email='[email protected]',
2322 license='MIT',
2423 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
24 long_description=open('README.rst').read(),
25 install_requires=install_requires,
26 classifiers=[
27 'Development Status :: 4 - Beta',
28 'Intended Audience :: Developers',
29 'License :: OSI Approved :: MIT License',
30 'Topic :: Software Development :: Testing',
31 'Programming Language :: Python :: 2',
32 'Programming Language :: Python :: 2.7',
33 'Programming Language :: Python :: 3',
34 'Programming Language :: Python :: 3.3',
35 'Programming Language :: Python :: 3.4',
36 'Programming Language :: Python :: 3.5',
37 'Programming Language :: Python :: 3.6',
38 'Programming Language :: Python :: 3.7',
39 ])
(New empty file)
0 # Copyright (c) 2008-2016 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
21 from mockito import when, unstub, verify
22 from mockito.verification import VerificationError
23
24 class Dog:
25 @classmethod
26 def bark(cls):
27 return "woof!"
28
29
30 class Cat:
31 @classmethod
32 def meow(cls, m):
33 return cls.__name__ + " " + str(m)
34
35
36 class Lion(object):
37 @classmethod
38 def roar(cls):
39 return "Rrrrr!"
40
41
42 class ClassMethodsTest(TestBase):
43
44 def tearDown(self):
45 unstub()
46
47 def testUnstubs(self):
48 when(Dog).bark().thenReturn("miau!")
49 unstub()
50 self.assertEqual("woof!", Dog.bark())
51
52 # TODO decent test case please :) without testing irrelevant implementation
53 # details
54 def testUnstubShouldPreserveMethodType(self):
55 when(Dog).bark().thenReturn("miau!")
56 unstub()
57 self.assertTrue(isinstance(Dog.__dict__.get("bark"), classmethod))
58
59 def testStubs(self):
60 self.assertEqual("woof!", Dog.bark())
61
62 when(Dog).bark().thenReturn("miau!")
63
64 self.assertEqual("miau!", Dog.bark())
65
66 def testStubsClassesDerivedFromTheObjectClass(self):
67 self.assertEqual("Rrrrr!", Lion.roar())
68
69 when(Lion).roar().thenReturn("miau!")
70
71 self.assertEqual("miau!", Lion.roar())
72
73 def testVerifiesMultipleCallsOnClassmethod(self):
74 when(Dog).bark().thenReturn("miau!")
75
76 Dog.bark()
77 Dog.bark()
78
79 verify(Dog, times=2).bark()
80
81 def testFailsVerificationOfMultipleCallsOnClassmethod(self):
82 when(Dog).bark().thenReturn("miau!")
83
84 Dog.bark()
85
86 self.assertRaises(VerificationError, verify(Dog, times=2).bark)
87
88 def testStubsAndVerifiesClassmethod(self):
89 when(Dog).bark().thenReturn("miau!")
90
91 self.assertEqual("miau!", Dog.bark())
92
93 verify(Dog).bark()
94
95 def testPreservesClassArgumentAfterUnstub(self):
96 self.assertEqual("Cat foo", Cat.meow("foo"))
97
98 when(Cat).meow("foo").thenReturn("bar")
99
100 self.assertEqual("bar", Cat.meow("foo"))
101
102 unstub()
103
104 self.assertEqual("Cat foo", Cat.meow("foo"))
105
106
0
1 import pytest
2
3
4 @pytest.fixture
5 def unstub():
6 from mockito import unstub
7 yield
8 unstub()
0
1 import pytest
2
3 from collections import namedtuple
4
5 from mockito import when, args, kwargs, invocation, mock
6
7
8 class Dog(object):
9 def bark(self, sound):
10 return "%s!" % sound
11
12 def waggle(self):
13 return 'waggle'
14
15 class CallSignature(namedtuple('CallSignature', 'args kwargs')):
16 def raises(self, reason):
17 return pytest.mark.xfail(self, raises=reason, strict=True)
18
19 def sig(*args, **kwargs):
20 return CallSignature(args, kwargs)
21
22
23 class TestCallMethodWithSignature:
24 def testNoArg(self):
25 rex = Dog()
26 when(rex).waggle().thenReturn('wuff')
27
28 assert rex.waggle() == 'wuff'
29
30 with pytest.raises(TypeError):
31 rex.waggle(1)
32 with pytest.raises(TypeError):
33 rex.waggle(Ellipsis)
34 with pytest.raises(TypeError):
35 rex.waggle(args)
36 with pytest.raises(TypeError):
37 rex.waggle(kwargs)
38 with pytest.raises(TypeError):
39 rex.waggle(*args)
40 with pytest.raises(TypeError):
41 rex.waggle(**kwargs)
42
43 def testExpectingSpecificInputAsPositionalArgument(self):
44 rex = Dog()
45 when(rex).bark(1).thenReturn('wuff')
46
47 assert rex.bark(1) == 'wuff'
48
49 with pytest.raises(invocation.InvocationError):
50 rex.bark(sound=1)
51 with pytest.raises(invocation.InvocationError):
52 rex.bark(Ellipsis)
53 with pytest.raises(invocation.InvocationError):
54 rex.bark(args)
55 with pytest.raises(invocation.InvocationError):
56 rex.bark(*args)
57 with pytest.raises(invocation.InvocationError):
58 rex.bark(kwargs)
59
60 with pytest.raises(TypeError):
61 rex.bark(1, 2)
62 with pytest.raises(TypeError):
63 rex.bark(wuff=1)
64 with pytest.raises(TypeError):
65 rex.bark(**kwargs)
66
67 def testExpectingSpecificInputAsKeyword(self):
68 rex = Dog()
69 when(rex).bark(sound=1).thenReturn('wuff')
70
71 assert rex.bark(sound=1) == 'wuff'
72
73 with pytest.raises(invocation.InvocationError):
74 rex.bark(1)
75 with pytest.raises(invocation.InvocationError):
76 rex.bark(Ellipsis)
77 with pytest.raises(invocation.InvocationError):
78 rex.bark(args)
79 with pytest.raises(invocation.InvocationError):
80 rex.bark(*args)
81 with pytest.raises(invocation.InvocationError):
82 rex.bark(kwargs)
83
84 with pytest.raises(TypeError):
85 rex.bark(1, 2)
86 with pytest.raises(TypeError):
87 rex.bark(wuff=1)
88 with pytest.raises(TypeError):
89 rex.bark(**kwargs)
90
91 def testExpectingStarKwargs(self):
92 rex = Dog()
93 when(rex).bark(**kwargs).thenReturn('wuff')
94
95 assert rex.bark(sound='miau') == 'wuff'
96
97 with pytest.raises(invocation.InvocationError):
98 rex.bark('miau')
99 with pytest.raises(invocation.InvocationError):
100 rex.bark(Ellipsis)
101 with pytest.raises(invocation.InvocationError):
102 rex.bark(kwargs)
103 with pytest.raises(invocation.InvocationError):
104 rex.bark(args)
105
106 with pytest.raises(TypeError):
107 rex.bark(wuff='miau')
108 with pytest.raises(TypeError):
109 rex.bark(**kwargs)
110
111 def testExpectingEllipsis(self):
112 rex = Dog()
113 when(rex).bark(Ellipsis).thenReturn('wuff')
114
115 assert rex.bark('miau') == 'wuff'
116 with pytest.raises(TypeError):
117 rex.bark('miau', 'miau')
118
119 assert rex.bark(sound='miau') == 'wuff'
120 with pytest.raises(TypeError):
121 rex.bark(wuff='miau')
122
123 assert rex.bark(Ellipsis) == 'wuff'
124 assert rex.bark(args) == 'wuff'
125 assert rex.bark(*args) == 'wuff'
126 assert rex.bark(kwargs) == 'wuff'
127
128 with pytest.raises(TypeError):
129 rex.bark(**kwargs) == 'wuff'
130
131 def testExpectingStarArgs(self):
132 rex = Dog()
133 when(rex).bark(*args).thenReturn('wuff')
134
135 assert rex.bark('miau') == 'wuff'
136
137 with pytest.raises(invocation.InvocationError):
138 rex.bark(sound='miau')
139 with pytest.raises(TypeError):
140 rex.bark(wuff='miau')
141
142 assert rex.bark(*args) == 'wuff'
143 assert rex.bark(Ellipsis) == 'wuff'
144
145 with pytest.raises(TypeError):
146 rex.bark(**kwargs)
147
148
149 class TestEllipsises:
150
151 # In python3 `bark(...)` is actually valid, but the tests must
152 # be downwards compatible to python 2
153
154 @pytest.mark.parametrize('call', [
155 sig(),
156 sig('Wuff'),
157 sig('Wuff', 'Wuff'),
158 sig('Wuff', then='Wuff'),
159 sig(then='Wuff'),
160 ])
161 def testEllipsisAsSoleArgumentAlwaysPasses(self, call):
162 rex = mock()
163 when(rex).bark(Ellipsis).thenReturn('Miau')
164
165 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
166
167
168 @pytest.mark.parametrize('call', [
169 sig('Wuff'),
170 sig('Wuff', 'Wuff'),
171 sig('Wuff', then='Wuff'),
172 ])
173 def testEllipsisAsSecondArgumentPasses(self, call):
174 rex = mock()
175 when(rex).bark('Wuff', Ellipsis).thenReturn('Miau')
176
177 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
178
179 @pytest.mark.parametrize('call', [
180 sig(),
181 sig(then='Wuff'),
182 ])
183 def testEllipsisAsSecondArgumentRejections(self, call):
184 rex = mock()
185 when(rex).bark('Wuff', Ellipsis).thenReturn('Miau')
186
187 with pytest.raises(AssertionError):
188 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
189
190
191 @pytest.mark.parametrize('call', [
192 sig(),
193 sig('Wuff'),
194 sig('Wuff', 'Wuff'),
195 ])
196 def testArgsAsSoleArgumentPasses(self, call):
197 rex = mock()
198 when(rex).bark(*args).thenReturn('Miau')
199
200 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
201
202 @pytest.mark.parametrize('call', [
203 sig('Wuff', then='Wuff'),
204 sig(then='Wuff'),
205 ])
206 def testArgsAsSoleArgumentRejections(self, call):
207 rex = mock()
208 when(rex).bark(*args).thenReturn('Miau')
209
210 with pytest.raises(AssertionError):
211 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
212
213
214 @pytest.mark.parametrize('call', [
215 sig('Wuff'),
216 sig('Wuff', 'Wuff'),
217 ])
218 def testArgsAsSecondArgumentPasses(self, call):
219 rex = mock()
220 when(rex).bark('Wuff', *args).thenReturn('Miau')
221
222 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
223
224 @pytest.mark.parametrize('call', [
225 sig(),
226 sig('Wuff', then='Wuff'),
227 sig(then='Wuff'),
228 ])
229 def testArgsAsSecondArgumentRejections(self, call):
230 rex = mock()
231 when(rex).bark('Wuff', *args).thenReturn('Miau')
232
233 with pytest.raises(AssertionError):
234 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
235
236
237 @pytest.mark.parametrize('call', [
238 sig('Wuff', then='Wuff'),
239 sig('Wuff', 'Wuff', then='Wuff'),
240
241 ])
242 def testArgsBeforeConcreteKwargPasses(self, call):
243 rex = mock()
244 when(rex).bark('Wuff', *args, then='Wuff').thenReturn('Miau')
245
246 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
247
248 @pytest.mark.parametrize('call', [
249 sig(),
250 sig('Wuff'),
251 sig('Wuff', 'Wuff'),
252 sig(then='Wuff'),
253
254 ])
255 def testArgsBeforeConcreteKwargRejections(self, call):
256 rex = mock()
257 when(rex).bark('Wuff', *args, then='Wuff').thenReturn('Miau')
258
259 with pytest.raises(AssertionError):
260 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
261
262
263 @pytest.mark.parametrize('call', [
264 sig(),
265 sig(then='Wuff'),
266 sig(then='Wuff', later='Waff')
267 ])
268 def testKwargsAsSoleArgumentPasses(self, call):
269 rex = mock()
270 when(rex).bark(**kwargs).thenReturn('Miau')
271
272 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
273
274 @pytest.mark.parametrize('call', [
275 sig('Wuff'),
276 sig('Wuff', 'Wuff'),
277 sig('Wuff', then='Wuff'),
278 sig('Wuff', 'Wuff', then='Wuff'),
279 ])
280 def testKwargsAsSoleArgumentRejections(self, call):
281 rex = mock()
282 when(rex).bark(**kwargs).thenReturn('Miau')
283
284 with pytest.raises(AssertionError):
285 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
286
287
288 @pytest.mark.parametrize('call', [
289 sig(then='Wuff'),
290 sig(then='Wuff', later='Waff'),
291 sig(later='Waff', then='Wuff'),
292 ])
293 def testKwargsAsSecondKwargPasses(self, call):
294 rex = mock()
295 when(rex).bark(then='Wuff', **kwargs).thenReturn('Miau')
296
297 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
298
299 @pytest.mark.parametrize('call', [
300 sig(),
301 sig('Wuff'),
302 sig('Wuff', 'Wuff'),
303 sig('Wuff', then='Wuff'),
304 sig('Wuff', 'Wuff', then='Wuff'),
305 sig(first='Wuff', later='Waff')
306 ])
307 def testKwargsAsSecondKwargRejections(self, call):
308 rex = mock()
309 when(rex).bark(then='Wuff', **kwargs).thenReturn('Miau')
310
311 with pytest.raises(AssertionError):
312 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
313
314
315 @pytest.mark.parametrize('call', [
316 sig('Wuff', then='Waff'),
317 sig('Wuff', 'Wuff', then='Waff'),
318 sig('Wuff', then='Waff', later='Woff'),
319 sig('Wuff', first="Wiff", then='Waff', later='Woff'),
320 sig('Wuff', 'Wuff', then='Waff', later="Woff"),
321 ])
322 def testCombinedArgsAndKwargsPasses(self, call):
323 rex = mock()
324 when(rex).bark('Wuff', *args, then='Waff', **kwargs).thenReturn('Miau')
325
326 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
327
328 @pytest.mark.parametrize('call', [
329 sig(),
330 sig('Wuff'),
331 sig('Wuff', 'Wuff'),
332 sig(later='Woff'),
333 sig('Wuff', later='Woff'),
334 ])
335 def testCombinedArgsAndKwargsRejections(self, call):
336 rex = mock()
337 when(rex).bark('Wuff', *args, then='Waff', **kwargs).thenReturn('Miau')
338
339 with pytest.raises(AssertionError):
340 assert rex.bark(*call.args, **call.kwargs) == 'Miau'
341
342
343 @pytest.mark.parametrize('call', [
344 sig(Ellipsis),
345 ])
346 def testEllipsisMustBeLastThing(self, call):
347 rex = mock()
348 when(rex).bark(*call.args, **call.kwargs).thenReturn('Miau')
349
350 @pytest.mark.parametrize('call', [
351 sig(Ellipsis, 'Wuff'),
352 sig(Ellipsis, then='Wuff'),
353 sig(Ellipsis, 'Wuff', then='Waff'),
354 ])
355 def testEllipsisMustBeLastThingRejections(self, call):
356 rex = mock()
357 with pytest.raises(TypeError):
358 when(rex).bark(*call.args, **call.kwargs).thenReturn('Miau')
359
360
361 def testArgsMustUsedAsStarArg(self):
362 rex = mock()
363 with pytest.raises(TypeError):
364 when(rex).bark(args).thenReturn('Miau')
365
366 def testKwargsMustBeUsedAsStarKwarg(self):
367 rex = mock()
368 with pytest.raises(TypeError):
369 when(rex).bark(kwargs).thenReturn('Miau')
370
371 with pytest.raises(TypeError):
372 when(rex).bark(*kwargs).thenReturn('Miau')
373
374 def testNiceFormattingForEllipsis(self):
375 m = mock()
376 m.strict = False
377 inv = invocation.StubbedInvocation(m, 'bark', None)
378 inv(Ellipsis)
379
380 assert repr(inv) == 'bark(...)'
381
382 def testNiceFormattingForArgs(self):
383 m = mock()
384 m.strict = False
385 inv = invocation.StubbedInvocation(m, 'bark', None)
386 inv(*args)
387
388 assert repr(inv) == 'bark(*args)'
389
390 def testNiceFormattingForKwargs(self):
391 m = mock()
392 m.strict = False
393 inv = invocation.StubbedInvocation(m, 'bark', None)
394 inv(**kwargs)
395
396 assert repr(inv) == 'bark(**kwargs)'
397
0 # Copyright (c) 2008-2016 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 pytest
21
22 from .test_base import TestBase
23 from mockito import (
24 mock, when, expect, unstub, ANY, verify, verifyNoMoreInteractions,
25 verifyZeroInteractions, verifyNoUnwantedInteractions,
26 verifyStubbedInvocationsAreUsed)
27 from mockito.invocation import InvocationError
28 from mockito.verification import VerificationError
29
30 pytestmark = pytest.mark.usefixtures("unstub")
31
32 class Dog(object):
33 def waggle(self):
34 return "Wuff!"
35
36 def bark(self, sound):
37 return "%s!" % sound
38
39 def do_default_bark(self):
40 return self.bark('Wau')
41
42 def __call__(self):
43 pass
44
45 class InstanceMethodsTest(TestBase):
46 def tearDown(self):
47 unstub()
48
49 def testUnstubClassMethod(self):
50 original_method = Dog.waggle
51 when(Dog).waggle().thenReturn('Nope!')
52
53 unstub()
54
55 rex = Dog()
56 self.assertEqual('Wuff!', rex.waggle())
57 self.assertEqual(original_method, Dog.waggle)
58
59 def testUnstubMockedInstanceMethod(self):
60 rex = Dog()
61 when(rex).waggle().thenReturn('Nope!')
62 assert rex.waggle() == 'Nope!'
63 unstub()
64 assert rex.waggle() == 'Wuff!'
65
66 def testUnstubMockedInstanceDoesNotHideTheClass(self):
67 when(Dog).waggle().thenReturn('Nope!')
68 rex = Dog()
69 when(rex).waggle().thenReturn('Sure!')
70 assert rex.waggle() == 'Sure!'
71
72 unstub()
73 assert rex.waggle() == 'Wuff!'
74
75
76 def testStubAnInstanceMethod(self):
77 when(Dog).waggle().thenReturn('Boing!')
78
79 rex = Dog()
80 self.assertEqual('Boing!', rex.waggle())
81
82 def testStubsAnInstanceMethodWithAnArgument(self):
83 when(Dog).bark('Miau').thenReturn('Wuff')
84
85 rex = Dog()
86 self.assertEqual('Wuff', rex.bark('Miau'))
87
88 def testInvokeAStubbedMethodFromAnotherMethod(self):
89 when(Dog).bark('Wau').thenReturn('Wuff')
90
91 rex = Dog()
92 self.assertEqual('Wuff', rex.do_default_bark())
93 verify(Dog).bark('Wau')
94
95 def testYouCantStubAnUnknownMethodInStrictMode(self):
96 try:
97 when(Dog).barks('Wau').thenReturn('Wuff')
98 self.fail(
99 'Stubbing an unknown method should have thrown a exception')
100 except InvocationError:
101 pass
102
103 def testStubUnknownMethodInLooseMode(self):
104 when(Dog, strict=False).walk()
105
106 rex = Dog()
107 rex.walk()
108
109 unstub()
110 with pytest.raises(AttributeError):
111 rex.walk
112 with pytest.raises(AttributeError):
113 Dog.walk
114
115 def testAddNewMethodOnInstanceInLooseMode(self):
116 rex = Dog()
117 when(rex, strict=False).walk()
118 rex.walk()
119
120 unstub()
121 with pytest.raises(AttributeError):
122 rex.walk
123
124 def testThrowEarlyIfCallingWithUnexpectedArgumentsInStrictMode(self):
125 rex = Dog()
126 when(rex).bark('Miau').thenReturn('Wuff')
127
128 with pytest.raises(InvocationError):
129 rex.bark('Shhh')
130
131 def testNiceErrorMessageOnUnexpectedCall(self):
132 theMock = mock(strict=True)
133 when(theMock).foo('bar')
134 when(theMock).foo(12, baz='boz')
135 when(theMock).bar('foo') # <==== omitted from output!
136
137 with pytest.raises(InvocationError) as exc:
138 theMock.foo(True, None)
139
140 assert str(exc.value) == '''
141 Called but not expected:
142
143 foo(True, None)
144
145 Stubbed invocations are:
146
147 foo('bar')
148 foo(12, baz='boz')
149
150 '''
151
152 def testStubCallableObject(self):
153 when(Dog).__call__().thenReturn('done')
154
155 rex = Dog() # <= important. not stubbed
156 assert rex() == 'done'
157
158 def testReturnNoneIfCallingWithUnexpectedArgumentsIfNotStrict(self):
159 when(Dog, strict=False).bark('Miau').thenReturn('Wuff')
160 rex = Dog()
161 self.assertEqual(None, rex.bark('Shhh'))
162
163 def testStubInstancesInsteadOfClasses(self):
164 rex = Dog()
165 when(rex).bark('Miau').thenReturn('Wuff')
166
167 self.assertEqual('Wuff', rex.bark('Miau'))
168 verify(rex, times=1).bark(ANY)
169
170 max = Dog()
171 self.assertEqual('Miau!', max.bark('Miau'))
172
173 def testUnstubInstance(self):
174 rex = Dog()
175 when(rex).bark('Miau').thenReturn('Wuff')
176
177 unstub()
178
179 assert rex.bark('Miau') == 'Miau!'
180
181
182 def testNoExplicitReturnValueMeansNone(self):
183 when(Dog).bark('Miau').thenReturn()
184 rex = Dog()
185
186 self.assertEqual(None, rex.bark('Miau'))
187
188 def testForgottenThenReturnMeansReturnNone(self):
189 when(Dog).bark('Miau')
190 when(Dog).waggle()
191 rex = Dog()
192
193 self.assertEqual(None, rex.bark('Miau'))
194 self.assertEqual(None, rex.waggle())
195
196 class TestVerifyInteractions:
197 class TestZeroInteractions:
198 def testVerifyNoMoreInteractionsWorks(self):
199 when(Dog).bark('Miau')
200 verifyNoMoreInteractions(Dog)
201
202 def testVerifyZeroInteractionsWorks(self):
203 when(Dog).bark('Miau')
204 verifyZeroInteractions(Dog)
205
206 class TestOneInteraction:
207 def testNothingVerifiedVerifyNoMoreInteractionsRaises(self):
208 when(Dog).bark('Miau')
209 rex = Dog()
210 rex.bark('Miau')
211 with pytest.raises(VerificationError):
212 verifyNoMoreInteractions(Dog)
213
214 def testIfVerifiedVerifyNoMoreInteractionsPasses(self):
215 when(Dog).bark('Miau')
216 rex = Dog()
217 rex.bark('Miau')
218 verify(Dog).bark('Miau')
219 verifyNoMoreInteractions(Dog)
220
221 def testNothingVerifiedVerifyZeroInteractionsRaises(self):
222 when(Dog).bark('Miau')
223 rex = Dog()
224 rex.bark('Miau')
225 with pytest.raises(VerificationError):
226 verifyZeroInteractions(Dog)
227
228 def testIfVerifiedVerifyZeroInteractionsStillRaises(self):
229 when(Dog).bark('Miau')
230 rex = Dog()
231 rex.bark('Miau')
232 verify(Dog).bark('Miau')
233 with pytest.raises(VerificationError):
234 verifyZeroInteractions(Dog)
235
236 class TestEnsureStubsAreUsed:
237 def testBarkOnUnusedStub(self):
238 when(Dog).bark('Miau')
239 with pytest.raises(VerificationError):
240 verifyStubbedInvocationsAreUsed(Dog)
241
242 class TestPassIfExplicitlyVerified:
243 @pytest.mark.parametrize('verification', [
244 {'times': 0},
245 {'between': [0, 3]}
246 ])
247 def testPassIfExplicitlyVerified(self, verification):
248 dog = mock()
249 when(dog).waggle().thenReturn('Sure')
250 verify(dog, **verification).waggle()
251
252 verifyStubbedInvocationsAreUsed(dog)
253
254 def testWildcardCallSignatureOnVerify(self):
255 dog = mock()
256 when(dog).waggle(1).thenReturn('Sure')
257 verify(dog, times=0).waggle(Ellipsis)
258
259 verifyStubbedInvocationsAreUsed(dog)
260
261 @pytest.mark.xfail(reason='Not implemented.')
262 def testPassIfVerifiedZeroInteractions(self):
263 dog = mock()
264 when(dog).waggle(1).thenReturn('Sure')
265 verifyZeroInteractions(dog)
266
267 verifyStubbedInvocationsAreUsed(dog)
268
269 @pytest.mark.xfail(reason='Not implemented.')
270 def testPassIfVerifiedNoMoreInteractions(self):
271 dog = mock()
272 when(dog).waggle(1).thenReturn('Sure')
273 verifyNoMoreInteractions(dog)
274
275 verifyStubbedInvocationsAreUsed(dog)
276
277 def testWildacardCallSignatureOnStub(self):
278 dog = mock()
279 when(dog).waggle(Ellipsis).thenReturn('Sure')
280 verify(dog, times=0).waggle(1)
281
282 verifyStubbedInvocationsAreUsed(dog)
283
284 def testPassIfExplicitlyVerified4(self):
285 dog = mock()
286 when(dog).waggle(1).thenReturn('Sure')
287 when(dog).waggle(2).thenReturn('Sure')
288 verify(dog, times=0).waggle(Ellipsis)
289
290 verifyStubbedInvocationsAreUsed(dog)
291
292 class TestPassIfImplicitlyVerifiedViaExpect:
293 @pytest.mark.parametrize('verification', [
294 {'times': 0},
295 {'between': [0, 3]}
296 ])
297 def testPassIfImplicitlyVerified(self, verification):
298 dog = mock()
299 expect(dog, **verification).waggle().thenReturn('Sure')
300
301 verifyStubbedInvocationsAreUsed(dog)
302
303 def testPassUsedOnceImplicitAnswer(self):
304 when(Dog).bark('Miau')
305 rex = Dog()
306 rex.bark('Miau')
307 verifyStubbedInvocationsAreUsed(Dog)
308
309 def testPassUsedOnce(self):
310 dog = mock()
311 when(dog).waggle().thenReturn('Sure')
312
313 dog.waggle()
314 verifyStubbedInvocationsAreUsed(dog)
315
316 def testFailSecondStubNotUsed(self):
317 when(Dog).bark('Miau')
318 when(Dog).waggle()
319 rex = Dog()
320 rex.bark('Miau')
321 with pytest.raises(VerificationError):
322 verifyStubbedInvocationsAreUsed(Dog)
323
324 def testFailSecondStubSameMethodUnused(self):
325 when(Dog).bark('Miau')
326 when(Dog).bark('Grrr')
327 rex = Dog()
328 rex.bark('Miau')
329 with pytest.raises(VerificationError):
330 verifyStubbedInvocationsAreUsed(Dog)
331
332 def testPassTwoStubsOnSameMethodUsed(self):
333 when(Dog).bark('Miau')
334 when(Dog).bark('Grrr')
335 rex = Dog()
336 rex.bark('Miau')
337 rex.bark('Grrr')
338 verifyStubbedInvocationsAreUsed(Dog)
339
340 def testPassOneCatchAllOneSpecificStubBothUsed(self):
341 when(Dog).bark(Ellipsis)
342 when(Dog).bark('Miau')
343 rex = Dog()
344 rex.bark('Miau')
345 rex.bark('Grrr')
346 verifyStubbedInvocationsAreUsed(Dog)
347
348 def testFailSecondAnswerUnused(self):
349 when(Dog).bark('Miau').thenReturn('Yep').thenReturn('Nop')
350 rex = Dog()
351 rex.bark('Miau')
352 with pytest.raises(VerificationError):
353 verifyStubbedInvocationsAreUsed(Dog)
354
355
356 @pytest.mark.usefixtures('unstub')
357 class TestImplicitVerificationsUsingExpect:
358
359 @pytest.fixture(params=[
360 {'times': 2},
361 {'atmost': 2},
362 {'between': [1, 2]}
363 ], ids=['times', 'atmost', 'between'])
364 def verification(self, request):
365 return request.param
366
367 def testFailImmediatelyIfWantedCountExceeds(self, verification):
368 rex = Dog()
369 expect(rex, **verification).bark('Miau').thenReturn('Wuff')
370 rex.bark('Miau')
371 rex.bark('Miau')
372
373 with pytest.raises(InvocationError):
374 rex.bark('Miau')
375
376 def testVerifyNoMoreInteractionsWorks(self, verification):
377 rex = Dog()
378 expect(rex, **verification).bark('Miau').thenReturn('Wuff')
379 rex.bark('Miau')
380 rex.bark('Miau')
381
382 verifyNoMoreInteractions(rex)
383
384 def testNoUnwantedInteractionsWorks(self, verification):
385 rex = Dog()
386 expect(rex, **verification).bark('Miau').thenReturn('Wuff')
387 rex.bark('Miau')
388 rex.bark('Miau')
389
390 verifyNoUnwantedInteractions(rex)
391
392 @pytest.mark.parametrize('verification', [
393 {'times': 2},
394 {'atleast': 2},
395 {'between': [1, 2]}
396 ], ids=['times', 'atleast', 'between'])
397 def testVerifyNoMoreInteractionsBarksIfUnsatisfied(self, verification):
398 rex = Dog()
399 expect(rex, **verification).bark('Miau').thenReturn('Wuff')
400
401 with pytest.raises(VerificationError):
402 verifyNoMoreInteractions(rex)
403
404 @pytest.mark.parametrize('verification', [
405 {'times': 2},
406 {'atleast': 2},
407 {'between': [1, 2]}
408 ], ids=['times', 'atleast', 'between'])
409 def testNoUnwantedInteractionsBarksIfUnsatisfied(self, verification):
410 rex = Dog()
411 expect(rex, **verification).bark('Miau').thenReturn('Wuff')
412
413 with pytest.raises(VerificationError):
414 verifyNoUnwantedInteractions(rex)
415
416 def testNoUnwantedInteractionsForAllRegisteredObjects(self):
417 rex = Dog()
418 mox = Dog()
419
420 expect(rex, times=1).bark('Miau')
421 expect(mox, times=1).bark('Miau')
422
423 rex.bark('Miau')
424 mox.bark('Miau')
425
426 verifyNoUnwantedInteractions()
427
428 def testUseWhenAndExpectTogetherVerifyNoUnwatedInteractions(self):
429 rex = Dog()
430 when(rex).waggle()
431 expect(rex, times=1).bark('Miau')
432
433 rex.waggle()
434 rex.bark('Miau')
435
436 verifyNoUnwantedInteractions()
437
438 def testExpectWitoutVerification(self):
439 rex = Dog()
440 expect(rex).bark('Miau').thenReturn('Wuff')
441 verifyNoMoreInteractions(rex)
442
443 rex.bark('Miau')
444 with pytest.raises(VerificationError):
445 verifyNoMoreInteractions(rex)
446
447 # Where to put this test? During first implementation I broke this
448 def testEnsureWhenGetsNotConfused(self):
449 m = mock()
450 when(m).foo(1).thenReturn()
451 m.foo(1)
452 with pytest.raises(VerificationError):
453 verifyNoMoreInteractions(m)
454
455 def testEnsureMultipleExpectsArentConfused(self):
456 rex = Dog()
457 expect(rex, times=1).bark('Miau').thenReturn('Wuff')
458 expect(rex, times=1).waggle().thenReturn('Wuff')
459 rex.bark('Miau')
460 rex.waggle()
461
0
1 import pytest
2
3 from mockito.utils import get_obj, get_obj_attr_tuple
4
5 import sys
6
7
8 PY3 = sys.version_info >= (3,)
9
10
11 def foo():
12 pass
13
14 class TestLateImports:
15
16 def testOs(self):
17 import os
18 assert get_obj('os') is os
19
20 def testOsPath(self):
21 import os.path
22 assert get_obj('os.path') is os.path
23
24 def testOsPathExists(self):
25 import os.path
26 assert get_obj('os.path.exists') is os.path.exists
27
28 def testOsPathWhatever(self):
29 with pytest.raises(AttributeError) as exc:
30 get_obj('os.path.whatever')
31
32 assert str(exc.value) == "module 'os.path' has no attribute 'whatever'"
33
34 def testOsPathExistsForever(self):
35 with pytest.raises(AttributeError) as exc:
36 get_obj('os.path.exists.forever')
37
38 assert str(exc.value) == \
39 "object 'os.path.exists' has no attribute 'forever'"
40
41 def testOsPathExistsForeverAndEver(self):
42 with pytest.raises(AttributeError) as exc:
43 get_obj('os.path.exists.forever.and.ever')
44
45 assert str(exc.value) == \
46 "object 'os.path.exists' has no attribute 'forever'"
47
48 def testUnknownMum(self):
49 with pytest.raises(ImportError) as exc:
50 assert get_obj('mum') is foo
51 if PY3:
52 assert str(exc.value) == "No module named 'mum'"
53 else:
54 assert str(exc.value) == "No module named mum"
55
56 def testUnknownMumFoo(self):
57 with pytest.raises(ImportError) as exc:
58 assert get_obj('mum.foo') is foo
59 if PY3:
60 assert str(exc.value) == "No module named 'mum'"
61 else:
62 assert str(exc.value) == "No module named mum"
63
64 def testReturnGivenObject(self):
65 import os
66 assert get_obj(os) == os
67 assert get_obj(os.path) == os.path
68 assert get_obj(2) == 2
69
70 def testDisallowRelativeImports(self):
71 with pytest.raises(TypeError):
72 get_obj('.mum')
73
74 class TestReturnTuple:
75 def testOs(self):
76 with pytest.raises(TypeError):
77 get_obj_attr_tuple('os')
78
79 def testOsPath(self):
80 import os
81 assert get_obj_attr_tuple('os.path') == (os, 'path')
82
83 def testOsPathExists(self):
84 import os
85 assert get_obj_attr_tuple('os.path.exists') == (os.path, 'exists')
86
87 def testOsPathExistsNot(self):
88 import os
89 assert get_obj_attr_tuple('os.path.exists.not') == (
90 os.path.exists, 'not')
91
92 def testDisallowRelativeImports(self):
93 with pytest.raises(TypeError):
94 get_obj('.mum')
95
96
0 # Copyright (c) 2008-2016 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
21 from mockito import mock, verify
22 from mockito.matchers import and_, or_, not_, eq, neq, lt, lte, gt, gte, \
23 any_, arg_that, contains, matches, captor, ANY, ARGS, KWARGS
24 import re
25
26
27 class TestConvenienceMatchers:
28 def testBuiltinAnyStandsForOurAny(self):
29 dummy = mock()
30 dummy.foo(1)
31 dummy.foo('a')
32 dummy.foo(True)
33
34 verify(dummy, times=3).foo(any)
35
36 dummy.foo(a=12)
37 verify(dummy).foo(a=any)
38
39 def testOurAnyCanBeUsedAsAType(self):
40 dummy = mock()
41 dummy.foo(1)
42 dummy.foo('a')
43 dummy.foo(True)
44 verify(dummy, times=3).foo(any_)
45
46
47 class TestAliases:
48 def testANY(self):
49 dummy = mock()
50 dummy.foo(1)
51 verify(dummy).foo(ANY)
52
53 def testARGS(self):
54 dummy = mock()
55 dummy.foo(1)
56 verify(dummy).foo(*ARGS)
57
58 def testKWARGS(self):
59 dummy = mock()
60 dummy.foo(a=1)
61 verify(dummy).foo(**KWARGS)
62
63
64 class MatchersTest(TestBase):
65 def testVerifiesUsingContainsMatcher(self):
66 ourMock = mock()
67 ourMock.foo("foobar")
68
69 verify(ourMock).foo(contains("foo"))
70 verify(ourMock).foo(contains("bar"))
71
72
73 class AndMatcherTest(TestBase):
74 def testShouldSatisfyIfAllMatchersAreSatisfied(self):
75 self.assertTrue(
76 and_(contains("foo"), contains("bar")).matches("foobar"))
77
78 def testShouldNotSatisfyIfOneOfMatchersIsNotSatisfied(self):
79 self.assertFalse(
80 and_(contains("foo"), contains("bam")).matches("foobar"))
81
82 def testShouldTreatNonMatchersAsEqMatcher(self):
83 self.assertTrue(and_("foo", any_(str)).matches("foo"))
84 self.assertFalse(and_("foo", any_(int)).matches("foo"))
85
86
87 class OrMatcherTest(TestBase):
88 def testShouldSatisfyIfAnyOfMatchersIsSatisfied(self):
89 self.assertTrue(
90 or_(contains("foo"), contains("bam")).matches("foobar"))
91
92 def testShouldNotSatisfyIfAllOfMatchersAreNotSatisfied(self):
93 self.assertFalse(
94 or_(contains("bam"), contains("baz")).matches("foobar"))
95
96 def testShouldTreatNonMatchersAsEqMatcher(self):
97 self.assertTrue(or_("foo", "bar").matches("foo"))
98 self.assertFalse(or_("foo", "bar").matches("bam"))
99
100
101 class NotMatcherTest(TestBase):
102 def testShouldSatisfyIfInnerMatcherIsNotSatisfied(self):
103 self.assertTrue(not_(contains("foo")).matches("bar"))
104
105 def testShouldNotSatisfyIfInnerMatcherIsSatisfied(self):
106 self.assertFalse(not_(contains("foo")).matches("foo"))
107
108 def testShouldTreatNonMatchersAsEqMatcher(self):
109 self.assertTrue(or_("foo", "bar").matches("foo"))
110
111
112 class EqMatcherTest(TestBase):
113 def testShouldSatisfyIfArgMatchesGivenValue(self):
114 self.assertTrue(eq("foo").matches("foo"))
115
116 def testShouldNotSatisfyIfArgDoesNotMatchGivenValue(self):
117 self.assertFalse(eq("foo").matches("bar"))
118
119
120 class NeqMatcherTest(TestBase):
121 def testShouldSatisfyIfArgDoesNotMatchGivenValue(self):
122 self.assertTrue(neq("foo").matches("bar"))
123
124 def testShouldNotSatisfyIfArgMatchesGivenValue(self):
125 self.assertFalse(neq("foo").matches("foo"))
126
127
128 class LtMatcherTest(TestBase):
129 def testShouldSatisfyIfArgIsLessThanGivenValue(self):
130 self.assertTrue(lt(5).matches(4))
131
132 def testShouldNotSatisfyIfArgIsEqualToGivenValue(self):
133 self.assertFalse(lt(5).matches(5))
134
135 def testShouldNotSatisfyIfArgIsGreaterThanGivenValue(self):
136 self.assertFalse(lt(5).matches(6))
137
138
139 class LteMatcherTest(TestBase):
140 def testShouldSatisfyIfArgIsLessThanGivenValue(self):
141 self.assertTrue(lte(5).matches(4))
142
143 def testShouldSatisfyIfArgIsEqualToGivenValue(self):
144 self.assertTrue(lte(5).matches(5))
145
146 def testShouldNotSatisfyIfArgIsGreaterThanGivenValue(self):
147 self.assertFalse(lte(5).matches(6))
148
149
150 class GtMatcherTest(TestBase):
151 def testShouldNotSatisfyIfArgIsLessThanGivenValue(self):
152 self.assertFalse(gt(5).matches(4))
153
154 def testShouldNotSatisfyIfArgIsEqualToGivenValue(self):
155 self.assertFalse(gt(5).matches(5))
156
157 def testShouldSatisfyIfArgIsGreaterThanGivenValue(self):
158 self.assertTrue(gt(5).matches(6))
159
160
161 class GteMatcherTest(TestBase):
162 def testShouldNotSatisfyIfArgIsLessThanGivenValue(self):
163 self.assertFalse(gte(5).matches(4))
164
165 def testShouldSatisfyIfArgIsEqualToGivenValue(self):
166 self.assertTrue(gte(5).matches(5))
167
168 def testShouldSatisfyIfArgIsGreaterThanGivenValue(self):
169 self.assertTrue(gte(5).matches(6))
170
171
172 class ArgThatMatcherTest(TestBase):
173 def testShouldSatisfyIfPredicateReturnsTrue(self):
174 self.assertTrue(arg_that(lambda arg: arg > 5).matches(10))
175
176 def testShouldNotSatisfyIfPredicateReturnsFalse(self):
177 self.assertFalse(arg_that(lambda arg: arg > 5).matches(1))
178
179
180 class ContainsMatcherTest(TestBase):
181 def testShouldSatisfiySubstringOfGivenString(self):
182 self.assertTrue(contains("foo").matches("foobar"))
183
184 def testShouldSatisfySameString(self):
185 self.assertTrue(contains("foobar").matches("foobar"))
186
187 def testShouldNotSatisfiyStringWhichIsNotSubstringOfGivenString(self):
188 self.assertFalse(contains("barfoo").matches("foobar"))
189
190 def testShouldNotSatisfiyEmptyString(self):
191 self.assertFalse(contains("").matches("foobar"))
192
193 def testShouldNotSatisfiyNone(self):
194 self.assertFalse(contains(None).matches("foobar"))
195
196
197 class MatchesMatcherTest(TestBase):
198 def testShouldSatisfyIfRegexMatchesGivenString(self):
199 self.assertTrue(matches('f..').matches('foo'))
200
201 def testShouldAllowSpecifyingRegexFlags(self):
202 self.assertFalse(matches('f..').matches('Foo'))
203 self.assertTrue(matches('f..', re.IGNORECASE).matches('Foo'))
204
205 def testShouldNotSatisfyIfRegexIsNotMatchedByGivenString(self):
206 self.assertFalse(matches('f..').matches('bar'))
207
208
209 class ArgumentCaptorTest(TestBase):
210 def testShouldSatisfyIfInnerMatcherIsSatisfied(self):
211 c = captor(contains("foo"))
212 self.assertTrue(c.matches("foobar"))
213
214 def testShouldNotSatisfyIfInnerMatcherIsNotSatisfied(self):
215 c = captor(contains("foo"))
216 self.assertFalse(c.matches("barbam"))
217
218 def testShouldReturnNoneValueByDefault(self):
219 c = captor(contains("foo"))
220 self.assertEqual(None, c.value)
221
222 def testShouldReturnNoneValueIfDidntMatch(self):
223 c = captor(contains("foo"))
224 c.matches("bar")
225 self.assertEqual(None, c.value)
226
227 def testShouldReturnLastMatchedValue(self):
228 c = captor(contains("foo"))
229 c.matches("foobar")
230 c.matches("foobam")
231 c.matches("bambaz")
232 self.assertEqual("foobam", c.value)
233
234 def testShouldDefaultMatcherToAny(self):
235 c = captor()
236 c.matches("foo")
237 c.matches(123)
238 self.assertEqual(123, c.value)
239
0 import pytest
1 from mockito import mock, when
2
3 def test_deprecated_a(unstub):
4 # Setting on `__class__` is confusing for users
5 m = mock()
6
7 prop = mock()
8 when(prop).__get__(Ellipsis).thenRaise(ValueError)
9 m.__class__.tx = prop
10
11 with pytest.raises(ValueError):
12 m.tx
13
14
15 def test_deprecated_b(unstub):
16 # Setting on `__class__` is confusing for users
17 m = mock()
18
19 def _raise(*a):
20 print(a)
21 raise ValueError('Boom')
22
23 m.__class__.tx = property(_raise)
24
25 with pytest.raises(ValueError):
26 m.tx
27
28
29 def test_deprecated_c(unstub):
30 # Setting on `__class__` is confusing for users
31 # Wrapping explicitly with `property` as well
32 m = mock()
33
34 prop = mock(strict=True)
35 when(prop).__call__(Ellipsis).thenRaise(ValueError)
36 m.__class__.tx = property(prop)
37
38 with pytest.raises(ValueError):
39 m.tx
40
41
42 def test_recommended_approach():
43 prop = mock(strict=True)
44 when(prop).__get__(Ellipsis).thenRaise(ValueError)
45
46 m = mock({'tx': prop})
47 with pytest.raises(ValueError):
48 m.tx
0
1 class Foo(object):
2 def no_arg(self):
3 pass
4
5
6 def one_arg(arg):
7 return arg
0 # Copyright (c) 2008-2016 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
22 from .test_base import TestBase
23 from mockito import when, unstub, verify, any
24 from mockito.invocation import InvocationError
25 from mockito.verification import VerificationError
26
27
28 class ModuleFunctionsTest(TestBase):
29 def tearDown(self):
30 unstub()
31
32 def testUnstubs(self):
33 when(os.path).exists("test").thenReturn(True)
34 unstub()
35 self.assertEqual(False, os.path.exists("test"))
36
37 def testStubs(self):
38 when(os.path).exists("test").thenReturn(True)
39
40 self.assertEqual(True, os.path.exists("test"))
41
42 def testStubsConsecutiveCalls(self):
43 when(os.path).exists("test").thenReturn(False).thenReturn(True)
44
45 self.assertEqual(False, os.path.exists("test"))
46 self.assertEqual(True, os.path.exists("test"))
47
48 def testStubsMultipleClasses(self):
49 when(os.path).exists("test").thenReturn(True)
50 when(os.path).dirname(any(str)).thenReturn("mocked")
51
52 self.assertEqual(True, os.path.exists("test"))
53 self.assertEqual("mocked", os.path.dirname("whoah!"))
54
55 def testVerifiesSuccesfully(self):
56 when(os.path).exists("test").thenReturn(True)
57
58 os.path.exists("test")
59
60 verify(os.path).exists("test")
61
62 def testFailsVerification(self):
63 when(os.path).exists("test").thenReturn(True)
64
65 self.assertRaises(VerificationError, verify(os.path).exists, "test")
66
67 def testFailsOnNumberOfCalls(self):
68 when(os.path).exists("test").thenReturn(True)
69
70 os.path.exists("test")
71
72 self.assertRaises(VerificationError, verify(os.path, times=2).exists,
73 "test")
74
75 def testStubsTwiceAndUnstubs(self):
76 when(os.path).exists("test").thenReturn(False)
77 when(os.path).exists("test").thenReturn(True)
78
79 self.assertEqual(True, os.path.exists("test"))
80
81 unstub()
82
83 self.assertEqual(False, os.path.exists("test"))
84
85 def testStubsTwiceWithDifferentArguments(self):
86 when(os.path).exists("Foo").thenReturn(False)
87 when(os.path).exists("Bar").thenReturn(True)
88
89 self.assertEqual(False, os.path.exists("Foo"))
90 self.assertEqual(True, os.path.exists("Bar"))
91
92 def testShouldThrowIfWeStubAFunctionNotDefinedInTheModule(self):
93 self.assertRaises(InvocationError,
94 lambda: when(os).walk_the_line().thenReturn(None))
95
96 def testEnsureWeCanMockTheClassOnAModule(self):
97 from . import module
98 when(module).Foo().thenReturn('mocked')
99 assert module.Foo() == 'mocked'
0
1 import pytest
2
3 from mockito.mock_registry import _Dict
4 from mockito.mocking import Mock
5
6
7 class TestCustomDictLike:
8
9 def testAssignKeyValuePair(self):
10 td = _Dict()
11 obj = {}
12 mock = Mock(None)
13
14 td[obj] = mock
15
16 def testGetValueForKey(self):
17 td = _Dict()
18 obj = {}
19 mock = Mock(None)
20 td[obj] = mock
21
22 assert td.get(obj) == mock
23
24 def testReplaceValueForSameKey(self):
25 td = _Dict()
26 obj = {}
27 mock1 = Mock(None)
28 mock2 = Mock(None)
29 td[obj] = mock1
30 td[obj] = mock2
31
32 assert td.pop(obj) == mock2
33 with pytest.raises(KeyError):
34 td.pop(obj)
35
36 def testPopKey(self):
37 td = _Dict()
38 obj = {}
39 mock = Mock(None)
40 td[obj] = mock
41
42 assert td.pop(obj) == mock
43 assert td.get(obj) is None
44
45 def testIterValues(self):
46 td = _Dict()
47 obj = {}
48 mock = Mock(None)
49 td[obj] = mock
50
51 assert td.values() == [mock]
52
53 def testClear(self):
54 td = _Dict()
55 obj = {}
56 mock = Mock(None)
57 td[obj] = mock
58
59 td.clear()
60 assert td.get(obj) is None
61
0 import mockito
1 from mockito import when, patch
2 import pytest
3
4 import numpy as np
5 from . import module
6
7
8 pytestmark = pytest.mark.usefixtures("unstub")
9
10
11 def xcompare(a, b):
12 if isinstance(a, mockito.matchers.Matcher):
13 return a.matches(b)
14
15 return np.array_equal(a, b)
16
17
18 class TestEnsureNumpyWorks:
19 def testEnsureNumpyArrayAllowedWhenStubbing(self):
20 array = np.array([1, 2, 3])
21 when(module).one_arg(array).thenReturn('yep')
22
23 with patch(mockito.invocation.MatchingInvocation.compare, xcompare):
24 assert module.one_arg(array) == 'yep'
25
26 def testEnsureNumpyArrayAllowedWhenCalling(self):
27 array = np.array([1, 2, 3])
28 when(module).one_arg(Ellipsis).thenReturn('yep')
29 assert module.one_arg(array) == 'yep'
30
0
1 import pytest
2
3 from mockito import when, args, kwargs, unstub
4
5 from collections import namedtuple
6
7
8 class CallSignature(namedtuple('CallSignature', 'args kwargs')):
9 def raises(self, reason):
10 return pytest.mark.xfail(self, raises=reason, strict=True)
11
12 def sig(*a, **kw):
13 return CallSignature(a, kw)
14
15
16 class SUT(object):
17 def none_args(self):
18 pass
19
20 def one_arg(self, a):
21 pass
22
23 def two_args(self, a, b):
24 pass
25
26 def star_arg(self, *args):
27 pass
28
29 def star_kwarg(self, **kwargs):
30 pass
31
32 def arg_plus_star_arg(self, a, *b):
33 pass
34
35 def arg_plus_star_kwarg(self, a, **b):
36 pass
37
38 def two_args_wt_default(self, a, b=None):
39 pass
40
41 def combination(self, a, b=None, *c, **d):
42 pass
43
44
45 class ClassMethods(object):
46 @classmethod
47 def none_args(cls):
48 pass
49
50 @classmethod
51 def one_arg(cls, a):
52 pass
53
54 @classmethod
55 def two_args(cls, a, b):
56 pass
57
58 @classmethod
59 def star_arg(cls, *a):
60 pass
61
62 @classmethod
63 def star_kwarg(cls, **kw):
64 pass
65
66 @classmethod
67 def arg_plus_star_arg(cls, a, *b):
68 pass
69
70 @classmethod
71 def arg_plus_star_kwarg(cls, a, **b):
72 pass
73
74 @classmethod
75 def two_args_wt_default(cls, a, b=None):
76 pass
77
78 @classmethod
79 def combination(cls, a, b=None, *c, **d):
80 pass
81
82
83 class StaticMethods(object):
84 @staticmethod
85 def none_args():
86 pass
87
88 @staticmethod
89 def one_arg(a):
90 pass
91
92 @staticmethod
93 def two_args(a, b):
94 pass
95
96 @staticmethod
97 def star_arg(*a):
98 pass
99
100 @staticmethod
101 def star_kwarg(**kw):
102 pass
103
104 @staticmethod
105 def arg_plus_star_arg(a, *b):
106 pass
107
108 @staticmethod
109 def arg_plus_star_kwarg(a, **b):
110 pass
111
112 @staticmethod
113 def two_args_wt_default(a, b=None):
114 pass
115
116 @staticmethod
117 def combination(a, b=None, *c, **d):
118 pass
119
120
121 @pytest.fixture(params=[
122 'instance',
123 'class',
124 'classmethods',
125 'staticmethods',
126 'staticmethods_2',
127 ])
128 def sut(request):
129 if request.param == 'instance':
130 yield SUT()
131 elif request.param == 'class':
132 yield SUT
133 elif request.param == 'classmethods':
134 yield ClassMethods
135 elif request.param == 'staticmethods':
136 yield StaticMethods
137 elif request.param == 'staticmethods_2':
138 yield StaticMethods()
139
140 unstub()
141
142
143 class TestSignatures:
144
145 class TestNoneArg:
146
147 @pytest.mark.parametrize('call', [
148 sig(),
149 sig(Ellipsis),
150 ])
151 def test_passing(self, sut, call):
152 when(sut).none_args(*call.args, **call.kwargs).thenReturn('stub')
153
154
155 @pytest.mark.parametrize('call', [
156 sig(12),
157 sig(*args),
158 sig(**kwargs),
159 sig(*args, **kwargs)
160 ])
161 def test_failing(self, sut, call):
162 with pytest.raises(TypeError):
163 when(sut).none_args(*call.args, **call.kwargs)
164
165
166 class TestOneArg:
167
168 @pytest.mark.parametrize('call', [
169 sig(12),
170 sig(a=12),
171
172 sig(Ellipsis),
173
174 sig(*args),
175 sig(*args, **kwargs),
176 sig(**kwargs),
177 ])
178 def test_passing(self, sut, call):
179 when(sut).one_arg(*call.args, **call.kwargs).thenReturn('stub')
180
181 @pytest.mark.parametrize('call', [
182 sig(12, 13),
183 sig(12, b=2),
184 sig(12, 13, 14),
185 sig(b=2),
186 sig(12, c=2),
187 sig(12, b=2, c=2),
188
189 sig(12, Ellipsis),
190
191 sig(1, *args),
192 sig(*args, a=1),
193 sig(*args, b=1),
194 sig(1, **kwargs),
195 ])
196 def test_failing(self, sut, call):
197 with pytest.raises(TypeError):
198 when(sut).one_arg(*call.args, **call.kwargs)
199
200
201 class TestTwoArgs:
202
203 # def two_args(a, b)
204 @pytest.mark.parametrize('call', [
205 sig(12, 13),
206 sig(12, b=2),
207
208 sig(Ellipsis),
209 sig(12, Ellipsis),
210
211 sig(*args),
212 sig(*args, **kwargs),
213 sig(12, *args),
214 sig(**kwargs),
215 sig(12, **kwargs),
216 sig(b=13, **kwargs),
217
218 ])
219 def test_passing(self, sut, call):
220 when(sut).two_args(*call.args, **call.kwargs)
221
222 @pytest.mark.parametrize('call', [
223 sig(12),
224 sig(12, 13, 14),
225 sig(b=2),
226 sig(12, c=2),
227 sig(12, b=2, c=2),
228
229 sig(12, 13, Ellipsis),
230 sig(12, 13, *args),
231 sig(12, b=13, *args),
232 sig(12, 13, **kwargs),
233 sig(12, b=13, **kwargs),
234 ])
235 def test_failing(self, sut, call):
236 with pytest.raises(TypeError):
237 when(sut).two_args(*call.args, **call.kwargs)
238
239 class TestStarArg:
240 # def star_arg(*args)
241 @pytest.mark.parametrize('call', [
242 sig(),
243 sig(12),
244 sig(12, 13),
245
246 sig(Ellipsis),
247 sig(12, Ellipsis),
248 sig(12, 13, Ellipsis),
249
250 sig(*args),
251 sig(12, *args),
252 sig(12, 13, *args)
253 ], ids=lambda i: str(i))
254 def test_passing(self, sut, call):
255 when(sut).star_arg(*call.args, **call.kwargs)
256
257 @pytest.mark.parametrize('call', [
258 sig(**kwargs),
259 sig(12, **kwargs),
260 sig(Ellipsis, **kwargs),
261 sig(a=12),
262 sig(args=12)
263 ], ids=lambda i: str(i))
264 def test_failing(self, sut, call):
265 with pytest.raises(TypeError):
266 when(sut).star_arg(*call.args, **call.kwargs)
267
268
269 class TestStarKwarg:
270 # def star_kwarg(**kwargs)
271 @pytest.mark.parametrize('call', [
272 sig(),
273 sig(a=1),
274 sig(a=1, b=2),
275
276 sig(Ellipsis),
277
278 sig(**kwargs),
279 sig(a=1, **kwargs)
280
281 ], ids=lambda i: str(i))
282 def test_passing(self, sut, call):
283 when(sut).star_kwarg(*call.args, **call.kwargs)
284
285 @pytest.mark.parametrize('call', [
286 sig(12),
287 sig(*args),
288 sig(*args, **kwargs),
289 sig(12, a=1)
290 ], ids=lambda i: str(i))
291 def test_failing(self, sut, call):
292 with pytest.raises(TypeError):
293 when(sut).star_kwarg(*call.args, **call.kwargs)
294
295
296 class TestArgPlusStarArg:
297 # def arg_plus_star_arg(a, *args)
298 @pytest.mark.parametrize('call', [
299 sig(12),
300 sig(a=12),
301 sig(12, 13),
302
303 sig(Ellipsis),
304 sig(12, Ellipsis),
305 sig(12, 13, Ellipsis),
306
307 sig(*args),
308 sig(12, *args),
309
310 sig(**kwargs),
311 ], ids=lambda i: str(i))
312 def test_passing(self, sut, call):
313 when(sut).arg_plus_star_arg(*call.args, **call.kwargs)
314
315 @pytest.mark.parametrize('call', [
316 sig(),
317 sig(13, a=12),
318
319 sig(b=13),
320 sig(12, b=13, *args),
321 sig(a=12, b=13, *args),
322
323 sig(12, **kwargs),
324 sig(a=12, **kwargs),
325 ], ids=lambda i: str(i))
326 def test_failing(self, sut, call):
327 with pytest.raises(TypeError):
328 when(sut).arg_plus_star_arg(*call.args, **call.kwargs)
329
330
331 class TestArgPlusStarKwarg:
332 # def arg_plus_star_kwarg(a, **kwargs)
333 @pytest.mark.parametrize('call', [
334 sig(12),
335 sig(a=12),
336 sig(12, b=1),
337
338 sig(Ellipsis),
339 sig(12, Ellipsis),
340
341 sig(**kwargs),
342 sig(12, **kwargs),
343 sig(a=12, **kwargs),
344 sig(12, b=1, **kwargs),
345 sig(a=12, b=1, **kwargs),
346
347 sig(*args),
348 sig(*args, b=1),
349
350 sig(*args, **kwargs)
351 ], ids=lambda i: str(i))
352 def test_passing(self, sut, call):
353 when(sut).arg_plus_star_kwarg(*call.args, **call.kwargs)
354
355 @pytest.mark.parametrize('call', [
356 sig(),
357 sig(12, 13),
358 sig(b=1),
359 sig(12, a=1),
360 sig(12, 13, Ellipsis),
361 sig(*args, a=1),
362 sig(12, *args)
363 ], ids=lambda i: str(i))
364 def test_failing(self, sut, call):
365 with pytest.raises(TypeError):
366 when(sut).arg_plus_star_kwarg(*call.args, **call.kwargs)
367
368
369
370
371 class TestTwoArgsWtDefault:
372
373 @pytest.mark.parametrize('call', [
374 sig(12),
375 sig(12, 13),
376 sig(12, b=2),
377
378 sig(Ellipsis),
379 sig(12, Ellipsis),
380
381 sig(*args),
382 sig(*args, **kwargs),
383 sig(12, *args),
384 sig(*args, b=2),
385 sig(**kwargs),
386 sig(12, **kwargs),
387 ], ids=lambda i: str(i))
388 def test_passing(self, sut, call):
389 when(sut).two_args_wt_default(
390 *call.args, **call.kwargs).thenReturn()
391
392
393 @pytest.mark.parametrize('call', [
394 sig(12, 13, 14),
395 sig(b=2),
396 sig(12, c=2),
397 sig(12, b=2, c=2),
398
399 sig(12, 13, Ellipsis),
400
401 sig(12, 13, *args),
402 sig(12, b=13, *args),
403 sig(12, c=13, *args),
404 sig(12, *args, b=2),
405 sig(*args, a=2),
406 sig(*args, c=2),
407 sig(12, 13, **kwargs),
408 sig(12, b=13, **kwargs),
409 sig(12, c=13, **kwargs),
410 ], ids=lambda i: str(i))
411 def test_failing(self, sut, call):
412 with pytest.raises(TypeError):
413 when(sut).two_args_wt_default(
414 *call.args, **call.kwargs).thenReturn()
415
416 class TestCombination:
417
418 # def combination(self, a, b=None, *c, **d)
419 @pytest.mark.parametrize('call', [
420 sig(12),
421 sig(12, 13),
422 sig(12, 13, 14),
423 sig(12, 13, 14, 15),
424
425 sig(Ellipsis),
426 sig(12, Ellipsis),
427 sig(12, 13, Ellipsis),
428 sig(12, 13, 14, Ellipsis),
429 sig(12, 13, 14, 15, Ellipsis)
430
431 ], ids=lambda i: str(i))
432 def test_passing(self, sut, call):
433 when(sut).combination(
434 *call.args, **call.kwargs).thenReturn()
435
436
437 @pytest.mark.parametrize('call', [
438 sig(12, 13, b=16),
439 ], ids=lambda i: str(i))
440 def test_failing(self, sut, call):
441 with pytest.raises(TypeError):
442 when(sut).combination(
443 *call.args, **call.kwargs).thenReturn()
444
445
446 class TestBuiltin:
447
448 def testBuiltinOpen(self):
449 try:
450 import builtins
451 except ImportError:
452 import __builtin__ as builtins
453
454 try:
455 when(builtins).open('foo')
456 finally: # just to be sure
457 unstub()
458
0 # Copyright (c) 2008-2016 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 pytest
21
22 from mockito.invocation import InvocationError
23 from mockito import mock, when, verify
24
25
26 class Foo(object):
27 def bar(self):
28 pass
29
30 class Action(object):
31 def no_arg(self):
32 pass
33
34 def run(self, arg):
35 return arg
36
37 def __call__(self, task):
38 return task
39
40
41 class TestSpeccing:
42 def testStubCallAndVerify(self):
43 action = mock(Action)
44
45 when(action).run(11).thenReturn(12)
46 assert action.run(11) == 12
47 verify(action).run(11)
48
49
50 def testShouldScreamWhenStubbingUnknownMethod(self):
51 action = mock(Action)
52
53 with pytest.raises(InvocationError):
54 when(action).unknownMethod()
55
56 def testShouldScreamWhenCallingUnknownMethod(self):
57 action = mock(Action)
58
59 with pytest.raises(AttributeError):
60 action.unknownMethod()
61
62 def testShouldScreamWhenCallingUnexpectedMethod(self):
63 action = mock(Action)
64
65 with pytest.raises(AttributeError):
66 action.run(11)
67
68 def testPreconfigureMockWithAttributes(self):
69 action = mock({'foo': 'bar'}, spec=Action)
70
71 assert action.foo == 'bar'
72 with pytest.raises(InvocationError):
73 when(action).remember()
74
75 def testPreconfigureWithFunction(self):
76 action = mock({
77 'run': lambda _: 12
78 }, spec=Action)
79
80 assert action.run(11) == 12
81
82 verify(action).run(11)
83
84 def testPreconfigureWithFunctionThatTakesNoArgs(self):
85 action = mock({
86 'no_arg': lambda: 12
87 }, spec=Action)
88
89 assert action.no_arg() == 12
90
91 verify(action).no_arg()
92
93 def testShouldScreamOnUnknownAttribute(self):
94 action = mock(Action)
95
96 with pytest.raises(AttributeError):
97 action.cam
98
99 def testShouldPassIsInstanceChecks(self):
100 action = mock(Action)
101
102 assert isinstance(action, Action)
103
104 def testHasANiceName(self):
105 action = mock(Action)
106
107 assert repr(action) == "<DummyAction id=%s>" % id(action)
108
109
110 class TestSpeccingLoose:
111 def testReturnNoneForEveryMethod(self):
112 action = mock(Action, strict=False)
113 assert action.unknownMethod() is None
114 assert action.run(11) is None
115
0 # Copyright (c) 2008-2016 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 pytest
21 import sys
22
23 from .test_base import TestBase
24 from mockito import (
25 when, spy, spy2, verify, VerificationError, verifyZeroInteractions)
26
27 import time
28
29 class Dummy(object):
30 def foo(self):
31 return "foo"
32
33 def bar(self):
34 raise TypeError
35
36 def return_args(self, *args, **kwargs):
37 return (args, kwargs)
38
39 @classmethod
40 def class_method(cls, arg):
41 return arg
42
43
44 class SpyingTest(TestBase):
45 def testPreservesReturnValues(self):
46 dummy = Dummy()
47 spiedDummy = spy(dummy)
48 self.assertEqual(dummy.foo(), spiedDummy.foo())
49
50 def testPreservesSideEffects(self):
51 dummy = spy(Dummy())
52 self.assertRaises(TypeError, dummy.bar)
53
54 def testPassesArgumentsCorrectly(self):
55 dummy = spy(Dummy())
56 self.assertEqual((('foo', 1), {'bar': 'baz'}),
57 dummy.return_args('foo', 1, bar='baz'))
58
59 def testIsVerifiable(self):
60 dummy = spy(Dummy())
61 dummy.foo()
62 verify(dummy).foo()
63 self.assertRaises(VerificationError, verify(dummy).bar)
64
65 def testVerifyZeroInteractionsWorks(self):
66 dummy = spy(Dummy())
67 verifyZeroInteractions(dummy)
68
69 def testRaisesAttributeErrorIfNoSuchMethod(self):
70 original = Dummy()
71 dummy = spy(original)
72 try:
73 dummy.lol()
74 self.fail("Should fail if no such method.")
75 except AttributeError as e:
76 self.assertEqual("You tried to call method 'lol' which '%s' "
77 "instance does not have." % original, str(e))
78
79 def testIsInstanceFakesOriginalClass(self):
80 dummy = spy(Dummy())
81
82 assert isinstance(dummy, Dummy)
83
84 def testHasNiceRepr(self):
85 dummy = spy(Dummy())
86
87 assert repr(dummy) == "<SpiedDummy id=%s>" % id(dummy)
88
89
90
91 def testCallClassmethod(self):
92 dummy = spy(Dummy)
93
94 assert dummy.class_method('foo') == 'foo'
95 verify(dummy).class_method('foo')
96
97
98 @pytest.mark.xfail(
99 sys.version_info >= (3,),
100 reason="python3 allows any value for self"
101 )
102 def testCantCallInstanceMethodWhenSpyingClass(self):
103 dummy = spy(Dummy)
104 with pytest.raises(TypeError):
105 dummy.return_args('foo')
106
107
108 def testModuleFunction(self):
109 import time
110 dummy = spy(time)
111
112 assert dummy.time() is not None
113
114 verify(dummy).time()
115
116
117 class TestSpy2:
118
119 def testA(self):
120 dummy = Dummy()
121 spy2(dummy.foo)
122
123 assert dummy.foo() == 'foo'
124 verify(dummy).foo()
125
126 def testB(self):
127 spy2(Dummy.class_method)
128
129 assert Dummy.class_method('foo') == 'foo'
130 verify(Dummy).class_method('foo')
131
132 def testModule(self):
133 spy2(time.time)
134
135 assert time.time() is not None
136 verify(time).time()
137
138 def testEnsureStubbedResponseForSpecificInvocation(self):
139 dummy = Dummy()
140 spy2(dummy.return_args)
141 when(dummy).return_args('foo').thenReturn('fox')
142
143 assert dummy.return_args('bar') == (('bar',), {})
144 assert dummy.return_args('box') == (('box',), {})
145 assert dummy.return_args('foo') == 'fox'
146
147 def testEnsureStubOrder(self):
148 dummy = Dummy()
149 when(dummy).return_args(Ellipsis).thenReturn('foo')
150 when(dummy).return_args('fox').thenReturn('fix')
151
152 assert dummy.return_args('bar') == 'foo'
153 assert dummy.return_args('box') == 'foo'
154 assert dummy.return_args('fox') == 'fix'
155
0 # Copyright (c) 2008-2016 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
21 from mockito import when, verify, unstub, any
22 from mockito.verification import VerificationError
23
24 class Dog:
25 @staticmethod
26 def bark():
27 return "woof"
28
29 @staticmethod
30 def barkHardly(*args):
31 return "woof woof"
32
33
34 class Cat:
35 @staticmethod
36 def meow():
37 return "miau"
38
39
40 class StaticMethodsTest(TestBase):
41
42 def tearDown(self):
43 unstub()
44
45 def testUnstubs(self):
46 when(Dog).bark().thenReturn("miau")
47 unstub()
48 self.assertEqual("woof", Dog.bark())
49
50 # TODO decent test case please :) without testing irrelevant implementation
51 # details
52 def testUnstubShouldPreserveMethodType(self):
53 when(Dog).bark().thenReturn("miau!")
54 unstub()
55 self.assertTrue(isinstance(Dog.__dict__.get("bark"), staticmethod))
56
57 def testStubs(self):
58 self.assertEqual("woof", Dog.bark())
59
60 when(Dog).bark().thenReturn("miau")
61
62 self.assertEqual("miau", Dog.bark())
63
64 def testStubsConsecutiveCalls(self):
65 when(Dog).bark().thenReturn(1).thenReturn(2)
66
67 self.assertEqual(1, Dog.bark())
68 self.assertEqual(2, Dog.bark())
69 self.assertEqual(2, Dog.bark())
70
71 def testStubsWithArgs(self):
72 self.assertEqual("woof woof", Dog.barkHardly(1, 2))
73
74 when(Dog).barkHardly(1, 2).thenReturn("miau")
75
76 self.assertEqual("miau", Dog.barkHardly(1, 2))
77
78 def testStubsButDoesNotMachArguments(self):
79 self.assertEqual("woof woof", Dog.barkHardly(1, "anything"))
80
81 when(Dog, strict=False).barkHardly(1, 2).thenReturn("miau")
82
83 self.assertEqual(None, Dog.barkHardly(1))
84
85 def testStubsMultipleClasses(self):
86 when(Dog).barkHardly(1, 2).thenReturn(1)
87 when(Dog).bark().thenReturn(2)
88 when(Cat).meow().thenReturn(3)
89
90 self.assertEqual(1, Dog.barkHardly(1, 2))
91 self.assertEqual(2, Dog.bark())
92 self.assertEqual(3, Cat.meow())
93
94 unstub()
95
96 self.assertEqual("woof", Dog.bark())
97 self.assertEqual("miau", Cat.meow())
98
99 def testVerifiesSuccesfully(self):
100 when(Dog).bark().thenReturn("boo")
101
102 Dog.bark()
103
104 verify(Dog).bark()
105
106 def testVerifiesWithArguments(self):
107 when(Dog).barkHardly(1, 2).thenReturn("boo")
108
109 Dog.barkHardly(1, 2)
110
111 verify(Dog).barkHardly(1, any())
112
113 def testFailsVerification(self):
114 when(Dog).bark().thenReturn("boo")
115
116 Dog.bark()
117
118 self.assertRaises(VerificationError, verify(Dog).barkHardly, (1, 2))
119
120 def testFailsOnInvalidArguments(self):
121 when(Dog).bark().thenReturn("boo")
122
123 Dog.barkHardly(1, 2)
124
125 self.assertRaises(VerificationError, verify(Dog).barkHardly, (1, 20))
126
127 def testFailsOnNumberOfCalls(self):
128 when(Dog).bark().thenReturn("boo")
129
130 Dog.bark()
131
132 self.assertRaises(VerificationError, verify(Dog, times=2).bark)
133
134 def testStubsAndVerifies(self):
135 when(Dog).bark().thenReturn("boo")
136
137 self.assertEqual("boo", Dog.bark())
138
139 verify(Dog).bark()
140
141 def testStubsTwiceAndUnstubs(self):
142 when(Dog).bark().thenReturn(1)
143 when(Dog).bark().thenReturn(2)
144
145 self.assertEqual(2, Dog.bark())
146
147 unstub()
148
149 self.assertEqual("woof", Dog.bark())
150
151 def testDoesNotVerifyStubbedCalls(self):
152 when(Dog).bark().thenReturn(1)
153
154 verify(Dog, times=0).bark()
155
0 # Copyright (c) 2008-2016 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 pytest
21
22 from .test_base import TestBase
23 from mockito import mock, when, verify, times, any
24
25
26 class TestEmptyMocks:
27 def testAllMethodsReturnNone(self):
28 dummy = mock()
29
30 assert dummy.foo() is None
31 assert dummy.foo(1, 2) is None
32
33
34 def testConfigureDummy(self):
35 dummy = mock({'foo': 'bar'})
36 assert dummy.foo == 'bar'
37
38 def testConfigureDummyWithFunction(self):
39 dummy = mock({
40 'getStuff': lambda s: s + ' thing'
41 })
42
43 assert dummy.getStuff('da') == 'da thing'
44 verify(dummy).getStuff('da')
45
46 def testDummiesAreCallable(self):
47 dummy = mock()
48 assert dummy() is None
49 assert dummy(1, 2) is None
50
51 def testCallsAreVerifiable(self):
52 dummy = mock()
53 dummy(1, 2)
54
55 verify(dummy).__call__(1, 2)
56
57 def testConfigureCallBehavior(self):
58 dummy = mock()
59 when(dummy).__call__(1).thenReturn(2)
60
61 assert dummy(1) == 2
62 verify(dummy).__call__(1)
63
64 def testCheckIsInstanceAgainstItself(self):
65 dummy = mock()
66 assert isinstance(dummy, dummy.__class__)
67
68
69 def testConfigureMagicMethod(self):
70 dummy = mock()
71 when(dummy).__getitem__(1).thenReturn(2)
72
73 assert dummy[1] == 2
74
75 class TestStrictEmptyMocks:
76 def testScream(self):
77 dummy = mock(strict=True)
78
79 with pytest.raises(AttributeError):
80 dummy.foo()
81
82 def testAllowStubbing(self):
83 dummy = mock(strict=True)
84 when(dummy).foo()
85 dummy.foo()
86 verify(dummy).foo()
87
88 def testCanConfigureCall(self):
89 dummy = mock(strict=True)
90 when(dummy).__call__(1).thenReturn(2)
91
92 assert dummy(1) == 2
93
94 def testScreamOnUnconfiguredCall(self):
95 dummy = mock(strict=True)
96
97 with pytest.raises(AttributeError):
98 dummy(1)
99
100 def testConfigureMagicMethod(self):
101 dummy = mock(strict=True)
102 when(dummy).__getitem__(1).thenReturn(2)
103
104 assert dummy[1] == 2
105
106
107 class StubbingTest(TestBase):
108 def testStubsWithReturnValue(self):
109 theMock = mock()
110 when(theMock).getStuff().thenReturn("foo")
111 when(theMock).getMoreStuff(1, 2).thenReturn(10)
112
113 self.assertEqual("foo", theMock.getStuff())
114 self.assertEqual(10, theMock.getMoreStuff(1, 2))
115 self.assertEqual(None, theMock.getMoreStuff(1, 3))
116
117 def testStubsWhenNoArgsGiven(self):
118 theMock = mock()
119 when(theMock).getStuff().thenReturn("foo")
120 when(theMock).getWidget().thenReturn("bar")
121
122 self.assertEqual("foo", theMock.getStuff())
123 self.assertEqual("bar", theMock.getWidget())
124
125 def testStubsConsecutivelyWhenNoArgsGiven(self):
126 theMock = mock()
127 when(theMock).getStuff().thenReturn("foo").thenReturn("bar")
128 when(theMock).getWidget().thenReturn("baz").thenReturn("baz2")
129
130 self.assertEqual("foo", theMock.getStuff())
131 self.assertEqual("bar", theMock.getStuff())
132 self.assertEqual("bar", theMock.getStuff())
133 self.assertEqual("baz", theMock.getWidget())
134 self.assertEqual("baz2", theMock.getWidget())
135 self.assertEqual("baz2", theMock.getWidget())
136
137 def testStubsWithException(self):
138 theMock = mock()
139 when(theMock).someMethod().thenRaise(Exception("foo"))
140
141 self.assertRaisesMessage("foo", theMock.someMethod)
142
143 def testStubsAndVerifies(self):
144 theMock = mock()
145 when(theMock).foo().thenReturn("foo")
146
147 self.assertEqual("foo", theMock.foo())
148 verify(theMock).foo()
149
150 def testStubsVerifiesAndStubsAgain(self):
151 theMock = mock()
152
153 when(theMock).foo().thenReturn("foo")
154 self.assertEqual("foo", theMock.foo())
155 verify(theMock).foo()
156
157 when(theMock).foo().thenReturn("next foo")
158 self.assertEqual("next foo", theMock.foo())
159 verify(theMock, times(2)).foo()
160
161 def testOverridesStubbing(self):
162 theMock = mock()
163
164 when(theMock).foo().thenReturn("foo")
165 when(theMock).foo().thenReturn("bar")
166
167 self.assertEqual("bar", theMock.foo())
168
169 def testStubsAndInvokesTwiceAndVerifies(self):
170 theMock = mock()
171
172 when(theMock).foo().thenReturn("foo")
173
174 self.assertEqual("foo", theMock.foo())
175 self.assertEqual("foo", theMock.foo())
176
177 verify(theMock, times(2)).foo()
178
179 def testStubsAndReturnValuesForSameMethodWithDifferentArguments(self):
180 theMock = mock()
181 when(theMock).getStuff(1).thenReturn("foo")
182 when(theMock).getStuff(1, 2).thenReturn("bar")
183
184 self.assertEqual("foo", theMock.getStuff(1))
185 self.assertEqual("bar", theMock.getStuff(1, 2))
186
187 def testStubsAndReturnValuesForSameMethodWithDifferentNamedArguments(self):
188 repo = mock()
189 when(repo).findby(id=6).thenReturn("John May")
190 when(repo).findby(name="John").thenReturn(["John May", "John Smith"])
191
192 self.assertEqual("John May", repo.findby(id=6))
193 self.assertEqual(["John May", "John Smith"], repo.findby(name="John"))
194
195 def testStubsForMethodWithSameNameAndNamedArgumentsInArbitraryOrder(self):
196 theMock = mock()
197
198 when(theMock).foo(first=1, second=2, third=3).thenReturn(True)
199
200 self.assertEqual(True, theMock.foo(third=3, first=1, second=2))
201
202 def testStubsMethodWithSameNameAndMixedArguments(self):
203 repo = mock()
204 when(repo).findby(1).thenReturn("John May")
205 when(repo).findby(1, active_only=True).thenReturn(None)
206 when(repo).findby(name="Sarah").thenReturn(["Sarah Connor"])
207 when(repo).findby(name="Sarah", active_only=True).thenReturn([])
208
209 self.assertEqual("John May", repo.findby(1))
210 self.assertEqual(None, repo.findby(1, active_only=True))
211 self.assertEqual(["Sarah Connor"], repo.findby(name="Sarah"))
212 self.assertEqual([], repo.findby(name="Sarah", active_only=True))
213
214 def testStubsWithChainedReturnValues(self):
215 theMock = mock()
216 when(theMock).getStuff().thenReturn("foo") \
217 .thenReturn("bar") \
218 .thenReturn("foobar")
219
220 self.assertEqual("foo", theMock.getStuff())
221 self.assertEqual("bar", theMock.getStuff())
222 self.assertEqual("foobar", theMock.getStuff())
223
224 def testStubsWithChainedReturnValuesAndException(self):
225 theMock = mock()
226 when(theMock).getStuff().thenReturn("foo") \
227 .thenReturn("bar") \
228 .thenRaise(Exception("foobar"))
229
230 self.assertEqual("foo", theMock.getStuff())
231 self.assertEqual("bar", theMock.getStuff())
232 self.assertRaisesMessage("foobar", theMock.getStuff)
233
234 def testStubsWithChainedExceptionAndReturnValue(self):
235 theMock = mock()
236 when(theMock).getStuff().thenRaise(Exception("foo")) \
237 .thenReturn("bar")
238
239 self.assertRaisesMessage("foo", theMock.getStuff)
240 self.assertEqual("bar", theMock.getStuff())
241
242 def testStubsWithChainedExceptions(self):
243 theMock = mock()
244 when(theMock).getStuff().thenRaise(Exception("foo")) \
245 .thenRaise(Exception("bar"))
246
247 self.assertRaisesMessage("foo", theMock.getStuff)
248 self.assertRaisesMessage("bar", theMock.getStuff)
249
250 def testStubsWithReturnValueBeingException(self):
251 theMock = mock()
252 exception = Exception("foo")
253 when(theMock).getStuff().thenReturn(exception)
254
255 self.assertEqual(exception, theMock.getStuff())
256
257 def testLastStubbingWins(self):
258 theMock = mock()
259 when(theMock).foo().thenReturn(1)
260 when(theMock).foo().thenReturn(2)
261
262 self.assertEqual(2, theMock.foo())
263
264 def testStubbingOverrides(self):
265 theMock = mock()
266 when(theMock).foo().thenReturn(1)
267 when(theMock).foo().thenReturn(2).thenReturn(3)
268
269 self.assertEqual(2, theMock.foo())
270 self.assertEqual(3, theMock.foo())
271 self.assertEqual(3, theMock.foo())
272
273 def testStubsWithMatchers(self):
274 theMock = mock()
275 when(theMock).foo(any()).thenReturn(1)
276
277 self.assertEqual(1, theMock.foo(1))
278 self.assertEqual(1, theMock.foo(100))
279
280 def testStubbingOverrides2(self):
281 theMock = mock()
282 when(theMock).foo(any()).thenReturn(1)
283 when(theMock).foo("oh").thenReturn(2)
284
285 self.assertEqual(2, theMock.foo("oh"))
286 self.assertEqual(1, theMock.foo("xxx"))
287
288 def testDoesNotVerifyStubbedCalls(self):
289 theMock = mock()
290 when(theMock).foo().thenReturn(1)
291
292 verify(theMock, times=0).foo()
293
294 def testStubsWithMultipleReturnValues(self):
295 theMock = mock()
296 when(theMock).getStuff().thenReturn("foo", "bar", "foobar")
297
298 self.assertEqual("foo", theMock.getStuff())
299 self.assertEqual("bar", theMock.getStuff())
300 self.assertEqual("foobar", theMock.getStuff())
301
302 def testStubsWithChainedMultipleReturnValues(self):
303 theMock = mock()
304 when(theMock).getStuff().thenReturn("foo", "bar") \
305 .thenReturn("foobar")
306
307 self.assertEqual("foo", theMock.getStuff())
308 self.assertEqual("bar", theMock.getStuff())
309 self.assertEqual("foobar", theMock.getStuff())
310
311 def testStubsWithMultipleExceptions(self):
312 theMock = mock()
313 when(theMock).getStuff().thenRaise(Exception("foo"), Exception("bar"))
314
315 self.assertRaisesMessage("foo", theMock.getStuff)
316 self.assertRaisesMessage("bar", theMock.getStuff)
317
318 def testStubsWithMultipleChainedExceptions(self):
319 theMock = mock()
320 when(theMock).getStuff() \
321 .thenRaise(Exception("foo"), Exception("bar")) \
322 .thenRaise(Exception("foobar"))
323
324 self.assertRaisesMessage("foo", theMock.getStuff)
325 self.assertRaisesMessage("bar", theMock.getStuff)
326 self.assertRaisesMessage("foobar", theMock.getStuff)
327
328 def testLeavesOriginalMethodUntouchedWhenCreatingStubFromRealClass(self):
329 class Person:
330 def get_name(self):
331 return "original name"
332
333 # given
334 person = Person()
335 mockPerson = mock(Person)
336
337 # when
338 when(mockPerson).get_name().thenReturn("stubbed name")
339
340 # then
341 self.assertEqual("stubbed name", mockPerson.get_name())
342 self.assertEqual("original name", person.get_name(),
343 'Original method should not be replaced.')
344
345 def testStubsWithThenAnswer(self):
346 m = mock()
347
348 when(m).magic_number().thenAnswer(lambda: 5)
349
350 self.assertEqual(m.magic_number(), 5)
351
352 when(m).add_one(any()).thenAnswer(lambda number: number + 1)
353
354 self.assertEqual(m.add_one(5), 6)
355 self.assertEqual(m.add_one(8), 9)
356
357 when(m).do_times(any(), any()).thenAnswer(lambda one, two: one * two)
358
359 self.assertEqual(m.do_times(5, 4), 20)
360 self.assertEqual(m.do_times(8, 5), 40)
361
362 when(m).do_dev_magic(any(), any()).thenAnswer(lambda a, b: a / b)
363
364 self.assertEqual(m.do_dev_magic(20, 4), 5)
365 self.assertEqual(m.do_dev_magic(40, 5), 8)
366
367 def test_key_words(testing="Magic"):
368 return testing + " Stuff"
369
370 when(m).with_key_words().thenAnswer(test_key_words)
371 self.assertEqual(m.with_key_words(), "Magic Stuff")
372
373 when(m).with_key_words(testing=any()).thenAnswer(test_key_words)
374 self.assertEqual(m.with_key_words(testing="Very Funky"),
375 "Very Funky Stuff")
376
377 def testSubsWithThenAnswerAndMixedArgs(self):
378 repo = mock()
379
380 def method_one(value, active_only=False):
381 return None
382
383 def method_two(name=None, active_only=False):
384 return ["%s Connor" % name]
385
386 def method_three(name=None, active_only=False):
387 return [name, active_only, 0]
388
389 when(repo).findby(1).thenAnswer(lambda x: "John May (%d)" % x)
390 when(repo).findby(1, active_only=True).thenAnswer(method_one)
391 when(repo).findby(name="Sarah").thenAnswer(method_two)
392 when(repo).findby(
393 name="Sarah", active_only=True).thenAnswer(method_three)
394
395 self.assertEqual("John May (1)", repo.findby(1))
396 self.assertEqual(None, repo.findby(1, active_only=True))
397 self.assertEqual(["Sarah Connor"], repo.findby(name="Sarah"))
398 self.assertEqual(
399 ["Sarah", True, 0], repo.findby(name="Sarah", active_only=True))
400
0 # Copyright (c) 2008-2016 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
23 class TestBase(unittest.TestCase):
24
25 def assertRaisesMessage(self, message, callable, *params):
26 try:
27 if (params):
28 callable(params)
29 else:
30 callable()
31 except Exception as e:
32 self.assertEqual(message, str(e))
33 else:
34 self.fail('Exception with message "%s" expected, but never raised'
35 % (message))
36
0 import pytest
1
2 from mockito import when, unstub, verify, ArgumentError
3
4
5 class Dog(object):
6 def waggle(self):
7 return 'Unsure'
8
9 def bark(self, sound='Wuff'):
10 return sound
11
12
13 class TestUntub:
14 def testIndependentUnstubbing(self):
15 rex = Dog()
16 mox = Dog()
17
18 when(rex).waggle().thenReturn('Yup')
19 when(mox).waggle().thenReturn('Nope')
20
21 assert rex.waggle() == 'Yup'
22 assert mox.waggle() == 'Nope'
23
24 unstub(rex)
25
26 assert rex.waggle() == 'Unsure'
27 assert mox.waggle() == 'Nope'
28
29 unstub(mox)
30
31 assert mox.waggle() == 'Unsure'
32
33 class TestAutomaticUnstubbing:
34
35 def testWith1(self):
36 rex = Dog()
37
38 with when(rex).waggle().thenReturn('Yup'):
39 assert rex.waggle() == 'Yup'
40 verify(rex).waggle()
41
42 assert rex.waggle() == 'Unsure'
43
44 def testWith2(self):
45 # Ensure the short version to return None works
46 rex = Dog()
47
48 with when(rex).waggle():
49 assert rex.waggle() is None
50 verify(rex).waggle()
51
52 assert rex.waggle() == 'Unsure'
53
54 def testWithRaisingSideeffect(self):
55 rex = Dog()
56
57 with pytest.raises(RuntimeError):
58 with when(rex).waggle().thenRaise(RuntimeError('Nope')):
59 rex.waggle()
60 assert rex.waggle() == 'Unsure'
61
62 def testNesting(self):
63 # That's not a real test, I just wanted to see how it would
64 # look like; bc you run out of space pretty quickly
65 rex = Dog()
66 mox = Dog()
67
68 with when(rex).waggle().thenReturn('Yup'):
69 with when(mox).waggle().thenReturn('Nope'):
70 assert rex.waggle() == 'Yup'
71
72 assert rex.waggle() == 'Unsure'
73 assert mox.waggle() == 'Unsure'
74 # though that's a good looking option
75 with when(rex).waggle().thenReturn('Yup'), \
76 when(mox).waggle().thenReturn('Nope'): # noqa: E127
77 assert rex.waggle() == 'Yup'
78 assert mox.waggle() == 'Nope'
79
80 assert rex.waggle() == 'Unsure'
81 assert mox.waggle() == 'Unsure'
82
83 def testOnlyUnstubTheExactStub(self):
84 rex = Dog()
85
86 when(rex).bark('Shhh').thenReturn('Nope')
87 with when(rex).bark('Miau').thenReturn('Grrr'):
88 assert rex.bark('Miau') == 'Grrr'
89
90 assert rex.bark('Shhh') == 'Nope'
91 verify(rex, times=2).bark(Ellipsis)
92
93 def testOnlyUnstubTheExcatMethod(self):
94 rex = Dog()
95
96 when(rex).bark('Shhh').thenReturn('Nope')
97 with when(rex).waggle().thenReturn('Yup'):
98 assert rex.waggle() == 'Yup'
99
100 assert rex.bark('Shhh') == 'Nope'
101 verify(rex, times=1).bark(Ellipsis)
102 verify(rex, times=1).waggle()
103
104 def testCleanupRegistryAfterLastStub(self):
105 rex = Dog()
106
107 with when(rex).bark('Shhh').thenReturn('Nope'):
108 with when(rex).bark('Miau').thenReturn('Grrr'):
109 assert rex.bark('Miau') == 'Grrr'
110 assert rex.bark('Shhh') == 'Nope'
111
112 with pytest.raises(ArgumentError):
113 verify(rex).bark(Ellipsis)
114
115
116 class TestEnsureCleanUnstubIfMockingAGlobal:
117 def testA(self):
118 with when(Dog).waggle().thenReturn('Sure'):
119 rex = Dog()
120 assert rex.waggle() == 'Sure'
121
122 verify(Dog).waggle()
123
124 def testB(self):
125 with when(Dog).waggle().thenReturn('Sure'):
126 rex = Dog()
127 assert rex.waggle() == 'Sure'
128
129 verify(Dog).waggle()
0 # Copyright (c) 2008-2016 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 pytest
21
22 from mockito import (mock, when, verify, VerificationError,
23 verifyNoMoreInteractions, verification)
24 from mockito.verification import never
25
26
27 class TestVerificationErrors:
28
29 def testPrintsNicelyNothingIfNeverUsed(self):
30 theMock = mock()
31 with pytest.raises(VerificationError) as exc:
32 verify(theMock).foo()
33 assert str(exc.value) == '''
34 Wanted but not invoked:
35
36 foo()
37
38 Instead got:
39
40 Nothing
41
42 '''
43
44 def testPrintsNicely(self):
45 theMock = mock()
46 theMock.foo('bar')
47 theMock.foo(12, baz='boz')
48 with pytest.raises(VerificationError) as exc:
49 verify(theMock).foo(True, None)
50 assert str(exc.value) == '''
51 Wanted but not invoked:
52
53 foo(True, None)
54
55 Instead got:
56
57 foo('bar')
58 foo(12, baz='boz')
59
60 '''
61
62 def testPrintOnlySameMethodInvocationsIfAny(self):
63 theMock = mock()
64 theMock.foo('bar')
65 theMock.bar('foo')
66
67 with pytest.raises(VerificationError) as exc:
68 verify(theMock).bar('fox')
69
70 assert str(exc.value) == '''
71 Wanted but not invoked:
72
73 bar('fox')
74
75 Instead got:
76
77 bar('foo')
78
79 '''
80
81 def testPrintAllInvocationsIfNoInvocationWithSameMethodName(self):
82 theMock = mock()
83 theMock.foo('bar')
84 theMock.bar('foo')
85
86 with pytest.raises(VerificationError) as exc:
87 verify(theMock).box('fox')
88
89 assert str(exc.value) == '''
90 Wanted but not invoked:
91
92 box('fox')
93
94 Instead got:
95
96 foo('bar')
97 bar('foo')
98
99 '''
100
101
102 def testPrintKeywordArgumentsNicely(self):
103 theMock = mock()
104 with pytest.raises(VerificationError) as exc:
105 verify(theMock).foo(foo='foo', one=1)
106 message = str(exc.value)
107 # We do not want to guarantee any order of arguments here
108 assert "foo='foo'" in message
109 assert "one=1" in message
110
111 def testPrintsOutThatTheActualAndExpectedInvocationCountDiffers(self):
112 theMock = mock()
113 when(theMock).foo().thenReturn(0)
114
115 theMock.foo()
116 theMock.foo()
117
118 with pytest.raises(VerificationError) as exc:
119 verify(theMock).foo()
120 assert "\nWanted times: 1, actual times: 2" == str(exc.value)
121
122 def testPrintsUnwantedInteraction(self):
123 theMock = mock()
124 theMock.foo(1, 'foo')
125 with pytest.raises(VerificationError) as exc:
126 verifyNoMoreInteractions(theMock)
127 assert "\nUnwanted interaction: foo(1, 'foo')" == str(exc.value)
128
129 def testPrintsNeverWantedInteractionsNicely(self):
130 theMock = mock()
131 theMock.foo()
132 with pytest.raises(VerificationError) as exc:
133 verify(theMock, never).foo()
134 assert "\nUnwanted invocation of foo(), times: 1" == str(exc.value)
135
136
137 class TestReprOfVerificationClasses:
138 def testTimes(self):
139 times = verification.Times(1)
140 assert repr(times) == "<Times wanted=1>"
141
142 def testAtLeast(self):
143 atleast = verification.AtLeast(2)
144 assert repr(atleast) == "<AtLeast wanted=2>"
145
146 def testAtMost(self):
147 atmost = verification.AtMost(3)
148 assert repr(atmost) == "<AtMost wanted=3>"
149
150 def testBetween(self):
151 between = verification.Between(1, 2)
152 assert repr(between) == "<Between [1, 2]>"
0 # Copyright (c) 2008-2016 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 pytest
21
22 from .test_base import TestBase
23 from mockito import (
24 mock, when, verify, forget_invocations, inorder, VerificationError,
25 ArgumentError, verifyNoMoreInteractions, verifyZeroInteractions,
26 verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed,
27 any)
28 from mockito.verification import never
29
30
31 class VerificationTestBase(TestBase):
32 def __init__(self, verification_function, *args, **kwargs):
33 self.verification_function = verification_function
34 TestBase.__init__(self, *args, **kwargs)
35
36 def setUp(self):
37 self.mock = mock()
38
39 def testVerifies(self):
40 self.mock.foo()
41 self.mock.someOtherMethod(1, "foo", "bar")
42
43 self.verification_function(self.mock).foo()
44 self.verification_function(self.mock).someOtherMethod(1, "foo", "bar")
45
46 def testVerifiesWhenMethodIsUsingKeywordArguments(self):
47 self.mock.foo()
48 self.mock.someOtherMethod(1, fooarg="foo", bararg="bar")
49
50 self.verification_function(self.mock).foo()
51 self.verification_function(self.mock).someOtherMethod(1, bararg="bar",
52 fooarg="foo")
53
54 def testVerifiesDetectsNamedArguments(self):
55 self.mock.foo(fooarg="foo", bararg="bar")
56
57 self.verification_function(self.mock).foo(bararg="bar", fooarg="foo")
58 try:
59 self.verification_function(self.mock).foo(bararg="foo",
60 fooarg="bar")
61 self.fail()
62 except VerificationError:
63 pass
64
65 def testKeywordArgumentsOrderIsUnimportant(self):
66 self.mock.blub(
67 line="blabla", runs="55", failures="1", errors="2")
68 self.verification_function(self.mock).blub(
69 runs="55", failures="1", errors="2", line="blabla")
70
71 def testFailsVerification(self):
72 self.mock.foo("boo")
73
74 self.assertRaises(VerificationError,
75 self.verification_function(self.mock).foo, "not boo")
76
77 def testVerifiesAnyTimes(self):
78 self.mock = mock()
79 self.mock.foo()
80
81 self.verification_function(self.mock).foo()
82 self.verification_function(self.mock).foo()
83 self.verification_function(self.mock).foo()
84
85 def testVerifiesMultipleCalls(self):
86 self.mock = mock()
87 self.mock.foo()
88 self.mock.foo()
89 self.mock.foo()
90
91 self.verification_function(self.mock, times=3).foo()
92
93 def testVerifiesMultipleCallsWhenMethodUsedAsFunction(self):
94 self.mock = mock()
95 f = self.mock.foo
96 f(1, 2)
97 f('foobar')
98
99 self.verification_function(self.mock).foo(1, 2)
100 self.verification_function(self.mock).foo('foobar')
101
102 def testFailsVerificationOfMultipleCalls(self):
103 self.mock = mock()
104 self.mock.foo()
105 self.mock.foo()
106 self.mock.foo()
107
108 self.assertRaises(VerificationError,
109 self.verification_function(self.mock, times=2).foo)
110
111 def testVerifiesUsingAnyMatcher(self):
112 self.mock.foo(1, "bar")
113
114 self.verification_function(self.mock).foo(1, any())
115 self.verification_function(self.mock).foo(any(), "bar")
116 self.verification_function(self.mock).foo(any(), any())
117
118 def testVerifiesUsingAnyIntMatcher(self):
119 self.mock.foo(1, "bar")
120
121 self.verification_function(self.mock).foo(any(int), "bar")
122
123 def testFailsVerificationUsingAnyIntMatcher(self):
124 self.mock.foo(1, "bar")
125
126 self.assertRaises(VerificationError,
127 self.verification_function(self.mock).foo, 1,
128 any(int))
129 self.assertRaises(VerificationError,
130 self.verification_function(self.mock).foo, any(int))
131
132 def testNumberOfTimesDefinedDirectlyInVerify(self):
133 self.mock.foo("bar")
134
135 self.verification_function(self.mock, times=1).foo("bar")
136
137 def testFailsWhenTimesIsLessThanZero(self):
138 self.assertRaises(ArgumentError, self.verification_function, None, -1)
139
140 def testVerifiesAtLeastTwoWhenMethodInvokedTwice(self):
141 self.mock.foo()
142 self.mock.foo()
143
144 self.verification_function(self.mock, atleast=2).foo()
145
146 def testVerifiesAtLeastTwoWhenMethodInvokedFourTimes(self):
147 self.mock.foo()
148 self.mock.foo()
149 self.mock.foo()
150 self.mock.foo()
151
152 self.verification_function(self.mock, atleast=2).foo()
153
154 def testFailsWhenMethodInvokedOnceForAtLeastTwoVerification(self):
155 self.mock.foo()
156 self.assertRaises(VerificationError,
157 self.verification_function(self.mock, atleast=2).foo)
158
159 def testVerifiesAtMostTwoWhenMethodInvokedTwice(self):
160 self.mock.foo()
161 self.mock.foo()
162
163 self.verification_function(self.mock, atmost=2).foo()
164
165 def testVerifiesAtMostTwoWhenMethodInvokedOnce(self):
166 self.mock.foo()
167
168 self.verification_function(self.mock, atmost=2).foo()
169
170 def testFailsWhenMethodInvokedFourTimesForAtMostTwoVerification(self):
171 self.mock.foo()
172 self.mock.foo()
173 self.mock.foo()
174 self.mock.foo()
175
176 self.assertRaises(VerificationError,
177 self.verification_function(self.mock, atmost=2).foo)
178
179 def testVerifiesBetween(self):
180 self.mock.foo()
181 self.mock.foo()
182
183 self.verification_function(self.mock, between=[1, 2]).foo()
184 self.verification_function(self.mock, between=[2, 3]).foo()
185 self.verification_function(self.mock, between=[1, 5]).foo()
186 self.verification_function(self.mock, between=[2, 2]).foo()
187
188 def testFailsVerificationWithBetween(self):
189 self.mock.foo()
190 self.mock.foo()
191 self.mock.foo()
192
193 self.assertRaises(VerificationError,
194 self.verification_function(self.mock,
195 between=[1, 2]).foo)
196 self.assertRaises(VerificationError,
197 self.verification_function(self.mock,
198 between=[4, 9]).foo)
199
200 def testFailsAtMostAtLeastAndBetweenVerificationWithWrongArguments(self):
201 self.assertRaises(ArgumentError, self.verification_function,
202 self.mock, atleast=0)
203 self.assertRaises(ArgumentError, self.verification_function,
204 self.mock, atleast=-5)
205 self.assertRaises(ArgumentError, self.verification_function,
206 self.mock, atmost=0)
207 self.assertRaises(ArgumentError, self.verification_function,
208 self.mock, atmost=-5)
209 self.assertRaises(ArgumentError, self.verification_function,
210 self.mock, between=[5, 1])
211 self.assertRaises(ArgumentError, self.verification_function,
212 self.mock, between=[-1, 1])
213 self.assertRaises(ArgumentError, self.verification_function,
214 self.mock, between=(0, 1, 2))
215 self.assertRaises(ArgumentError, self.verification_function,
216 self.mock, between=0)
217 self.assertRaises(ArgumentError, self.verification_function,
218 self.mock, atleast=5, atmost=5)
219 self.assertRaises(ArgumentError, self.verification_function,
220 self.mock, atleast=5, between=[1, 2])
221 self.assertRaises(ArgumentError, self.verification_function,
222 self.mock, atmost=5, between=[1, 2])
223 self.assertRaises(ArgumentError, self.verification_function,
224 self.mock, atleast=5, atmost=5, between=[1, 2])
225
226 def runTest(self):
227 pass
228
229
230 class VerifyTest(VerificationTestBase):
231 def __init__(self, *args, **kwargs):
232 VerificationTestBase.__init__(self, verify, *args, **kwargs)
233
234 def testVerifyNeverCalled(self):
235 verify(self.mock, never).someMethod()
236
237 def testVerifyNeverCalledRaisesError(self):
238 self.mock.foo()
239 self.assertRaises(VerificationError, verify(self.mock, never).foo)
240
241
242 class InorderVerifyTest(VerificationTestBase):
243 def __init__(self, *args, **kwargs):
244 VerificationTestBase.__init__(self, inorder.verify, *args, **kwargs)
245
246 def setUp(self):
247 self.mock = mock()
248
249 def testPassesIfOneIteraction(self):
250 self.mock.first()
251 inorder.verify(self.mock).first()
252
253 def testPassesIfMultipleInteractions(self):
254 self.mock.first()
255 self.mock.second()
256 self.mock.third()
257
258 inorder.verify(self.mock).first()
259 inorder.verify(self.mock).second()
260 inorder.verify(self.mock).third()
261
262 def testFailsIfNoInteractions(self):
263 self.assertRaises(VerificationError, inorder.verify(self.mock).first)
264
265 def testFailsIfWrongOrderOfInteractions(self):
266 self.mock.first()
267 self.mock.second()
268
269 self.assertRaises(VerificationError, inorder.verify(self.mock).second)
270
271 def testErrorMessage(self):
272 self.mock.second()
273 self.mock.first()
274 self.assertRaisesMessage(
275 '\nWanted first() to be invoked,\ngot second() instead.',
276 inorder.verify(self.mock).first)
277
278
279 def testPassesMixedVerifications(self):
280 self.mock.first()
281 self.mock.second()
282
283 verify(self.mock).first()
284 verify(self.mock).second()
285
286 inorder.verify(self.mock).first()
287 inorder.verify(self.mock).second()
288
289 def testFailsMixedVerifications(self):
290 self.mock.second()
291 self.mock.first()
292
293 # first - normal verifications, they should pass
294 verify(self.mock).first()
295 verify(self.mock).second()
296
297 # but, inorder verification should fail
298 self.assertRaises(VerificationError, inorder.verify(self.mock).first)
299
300
301 class VerifyNoMoreInteractionsTest(TestBase):
302 def testVerifies(self):
303 mockOne, mockTwo = mock(), mock()
304 mockOne.foo()
305 mockTwo.bar()
306
307 verify(mockOne).foo()
308 verify(mockTwo).bar()
309 verifyNoMoreInteractions(mockOne, mockTwo)
310
311 def testFails(self):
312 theMock = mock()
313 theMock.foo()
314 self.assertRaises(VerificationError, verifyNoMoreInteractions, theMock)
315
316
317 class VerifyZeroInteractionsTest(TestBase):
318 def testVerifies(self):
319 theMock = mock()
320 verifyZeroInteractions(theMock)
321 theMock.foo()
322 self.assertRaises(
323 VerificationError, verifyNoMoreInteractions, theMock)
324
325
326 class ClearInvocationsTest(TestBase):
327 def testClearsInvocations(self):
328 theMock1 = mock()
329 theMock2 = mock()
330 theMock1.do_foo()
331 theMock2.do_bar()
332
333 self.assertRaises(VerificationError, verifyZeroInteractions, theMock1)
334 self.assertRaises(VerificationError, verifyZeroInteractions, theMock2)
335
336 forget_invocations(theMock1, theMock2)
337
338 verifyZeroInteractions(theMock1)
339 verifyZeroInteractions(theMock2)
340
341 def testPreservesStubs(self):
342 theMock = mock()
343 when(theMock).do_foo().thenReturn('hello')
344 self.assertEqual('hello', theMock.do_foo())
345
346 forget_invocations(theMock)
347
348 self.assertEqual('hello', theMock.do_foo())
349
350
351 class TestRaiseOnUnknownObjects:
352 @pytest.mark.parametrize('verification_fn', [
353 verify,
354 verifyNoMoreInteractions,
355 verifyZeroInteractions,
356 verifyNoUnwantedInteractions,
357 verifyStubbedInvocationsAreUsed
358 ])
359 def testVerifyShouldRaise(self, verification_fn):
360 class Foo(object):
361 pass
362
363 with pytest.raises(ArgumentError) as exc:
364 verification_fn(Foo)
365 assert str(exc.value) == "obj '%s' is not registered" % Foo
366
367
0
1 import pytest
2
3 from mockito import when2, patch, spy2, verify
4 from mockito.utils import newmethod
5
6
7 import os
8
9
10 pytestmark = pytest.mark.usefixtures("unstub")
11
12
13 class Dog(object):
14 def bark(self, sound):
15 return sound
16
17 def bark_hard(self, sound):
18 return sound + '!'
19
20
21 class TestMockito2:
22 def testWhen2(self):
23 rex = Dog()
24 when2(rex.bark, 'Miau').thenReturn('Wuff')
25 when2(rex.bark, 'Miau').thenReturn('Grrr')
26 assert rex.bark('Miau') == 'Grrr'
27
28
29 def testPatch(self):
30 rex = Dog()
31 patch(rex.bark, lambda sound: sound + '!')
32 assert rex.bark('Miau') == 'Miau!'
33
34
35 def testPatch2(self):
36 rex = Dog()
37 patch(rex.bark, rex.bark_hard)
38 assert rex.bark('Miau') == 'Miau!'
39
40 def testPatch3(self):
41 rex = Dog()
42
43 def f(self, sound):
44 return self.bark_hard(sound)
45
46 f = newmethod(f, rex)
47 patch(rex.bark, f)
48
49 assert rex.bark('Miau') == 'Miau!'
50
51 def testAddFnWithPatch(self):
52 rex = Dog()
53
54 patch(rex, 'newfn', lambda s: s)
55 assert rex.newfn('Hi') == 'Hi'
56
57
58 class TestFancyObjResolver:
59 def testWhen2WithArguments(self):
60 # This test is a bit flaky bc pytest does not like a patched
61 # `os.path.exists` module.
62 when2(os.path.commonprefix, '/Foo').thenReturn(False)
63 when2(os.path.commonprefix, '/Foo').thenReturn(True)
64 when2(os.path.exists, '/Foo').thenReturn(True)
65
66 assert os.path.commonprefix('/Foo')
67 assert os.path.exists('/Foo')
68
69 def testWhen2WithoutArguments(self):
70 import time
71 when2(time.time).thenReturn('None')
72 assert time.time() == 'None'
73
74 def testWhenSplitOnNextLine(self):
75 # fmt: off
76 when2(
77 os.path.commonprefix, '/Foo').thenReturn(True)
78 # fmt: on
79 assert os.path.commonprefix('/Foo')
80
81 def testEnsureWithWhen2SameLine(self):
82 with when2(os.path.commonprefix, '/Foo'):
83 pass
84
85 def testEnsureWithWhen2SplitLine(self):
86 # fmt: off
87 with when2(
88 os.path.commonprefix, '/Foo'):
89 pass
90 # fmt: on
91
92 def testEnsureToResolveMethodOnClass(self):
93 class A(object):
94 class B(object):
95 def c(self):
96 pass
97
98 when2(A.B.c)
99
100 def testEnsureToResolveClass(self):
101 class A(object):
102 class B(object):
103 pass
104
105 when2(A.B, 'Hi').thenReturn('Ho')
106 assert A.B('Hi') == 'Ho'
107
108
109 def testPatch(self):
110 patch(os.path.commonprefix, lambda m: 'yup')
111 patch(os.path.commonprefix, lambda m: 'yep')
112
113 assert os.path.commonprefix(Ellipsis) == 'yep'
114
115 def testWithPatchGivenTwoArgs(self):
116 with patch(os.path.exists, lambda m: 'yup'):
117 assert os.path.exists('foo') == 'yup'
118
119 assert not os.path.exists('foo')
120
121 def testWithPatchGivenThreeArgs(self):
122 with patch(os.path, 'exists', lambda m: 'yup'):
123 assert os.path.exists('foo') == 'yup'
124
125 assert not os.path.exists('foo')
126
127 def testSpy2(self):
128 spy2(os.path.exists)
129
130 assert os.path.exists('/Foo') is False
131
132 verify(os.path).exists('/Foo')
133
134 class TestRejections:
135 def testA(self):
136 with pytest.raises(TypeError) as exc:
137 when2(os)
138 assert str(exc.value) == "can't guess origin of 'os'"
139
140 cp = os.path.commonprefix
141 with pytest.raises(TypeError) as exc:
142 spy2(cp)
143 assert str(exc.value) == "can't guess origin of 'cp'"
144
145 ptch = patch
146 with pytest.raises(TypeError) as exc:
147 ptch(os.path.exists, lambda: 'boo')
148 assert str(exc.value) == "could not destructure first argument"
0
1 import pytest
2
3 from mockito import when, when2, expect, verify, patch, mock, spy2
4 from mockito.invocation import InvocationError
5
6 class Dog(object):
7 def bark(self):
8 pass
9
10
11 class Unhashable(object):
12 def update(self, **kwargs):
13 pass
14
15 def __hash__(self):
16 raise TypeError("I'm immutable")
17
18
19 @pytest.mark.usefixtures('unstub')
20 class TestUserExposedInterfaces:
21
22 def testWhen(self):
23 whening = when(Dog)
24 assert whening.__dict__ == {}
25
26 def testExpect(self):
27 expecting = expect(Dog)
28 assert expecting.__dict__ == {}
29
30 def testVerify(self):
31 dummy = mock()
32 verifying = verify(dummy)
33 assert verifying.__dict__ == {}
34
35
36 def testEnsureUnhashableObjectCanBeMocked(self):
37 obj = Unhashable()
38 when(obj).update().thenReturn(None)
39
40
41 @pytest.mark.usefixtures('unstub')
42 class TestPassAroundStrictness:
43
44 def testReconfigureStrictMock(self):
45 when(Dog).bark() # important first call, inits theMock
46
47 when(Dog, strict=False).waggle().thenReturn('Sure')
48 expect(Dog, strict=False).weggle().thenReturn('Sure')
49
50
51 with pytest.raises(InvocationError):
52 when(Dog).wuggle()
53
54 with pytest.raises(InvocationError):
55 when(Dog).woggle()
56
57 rex = Dog()
58 assert rex.waggle() == 'Sure'
59 assert rex.weggle() == 'Sure'
60
61 # For documentation; the inital strict value of the mock will be used
62 # here. So the above when(..., strict=False) just assures we can
63 # actually *add* an attribute to the mocked object
64 with pytest.raises(InvocationError):
65 rex.waggle(1)
66
67 verify(Dog).waggle()
68 verify(Dog).weggle()
69
70 def testReconfigureLooseMock(self):
71 when(Dog, strict=False).bark() # important first call, inits theMock
72
73 when(Dog, strict=False).waggle().thenReturn('Sure')
74 expect(Dog, strict=False).weggle().thenReturn('Sure')
75
76 with pytest.raises(InvocationError):
77 when(Dog).wuggle()
78
79 with pytest.raises(InvocationError):
80 when(Dog).woggle()
81
82 rex = Dog()
83 assert rex.waggle() == 'Sure'
84 assert rex.weggle() == 'Sure'
85
86 # For documentation; see test above. strict is inherited from the
87 # initial mock. So we return `None`
88 assert rex.waggle(1) is None
89
90 verify(Dog).waggle()
91 verify(Dog).weggle()
92
93 # Where to put this test?
94 def testEnsureAddedAttributesGetRemovedOnUnstub(self):
95 with when(Dog, strict=False).wggle():
96 pass
97
98 with pytest.raises(AttributeError):
99 getattr(Dog, 'wggle')
100
101
102 @pytest.mark.usefixtures('unstub')
103 class TestDottedPaths:
104
105 def testWhen(self):
106 when('os.path').exists('/Foo').thenReturn(True)
107
108 import os.path
109 assert os.path.exists('/Foo')
110
111 def testWhen2(self):
112 when2('os.path.exists', '/Foo').thenReturn(True)
113
114 import os.path
115 assert os.path.exists('/Foo')
116
117 def testPatch(self):
118 dummy = mock()
119 patch('os.path.exists', dummy)
120
121 import os.path
122 assert os.path.exists('/Foo') is None
123
124 verify(dummy).__call__('/Foo')
125
126 def testVerify(self):
127 when('os.path').exists('/Foo').thenReturn(True)
128
129 import os.path
130 os.path.exists('/Foo')
131
132 verify('os.path', times=1).exists('/Foo')
133
134 def testSpy2(self):
135 spy2('os.path.exists')
136
137 import os.path
138 assert not os.path.exists('/Foo')
139
140 verify('os.path', times=1).exists('/Foo')