pax_global_header00006660000000000000000000000064137260763710014526gustar00rootroot0000000000000052 comment=e4c5ec8395b447bbfe22a80fd0bbdf0fca1bed37 mockito-python-1.2.2/000077500000000000000000000000001372607637100145145ustar00rootroot00000000000000mockito-python-1.2.2/.bumpversion.cfg000066400000000000000000000006161372607637100176270ustar00rootroot00000000000000[bumpversion] current_version = 1.2.2 commit = True message = Bump version to {new_version} tag = True tag_name = {new_version} parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+))? serialize = {major}.{minor}.{patch}-{release} {major}.{minor}.{patch} [bumpversion:file:mockito/__init__.py] [bumpversion:part:release] optional_value = release values = dev release mockito-python-1.2.2/.flake8000066400000000000000000000002531372607637100156670ustar00rootroot00000000000000[flake8] ignore = D, W291, W293, W391, W503, E302, E303, E306, E731 exclude = .git,.cache,docs,.env,.build,build max-complexity = 10 max-line-length = 79mockito-python-1.2.2/.gitignore000066400000000000000000000000701372607637100165010ustar00rootroot00000000000000*.pyc build docs/_build .eggs/ .pytest_cache __pycache__mockito-python-1.2.2/.travis.yml000066400000000000000000000021521372607637100166250ustar00rootroot00000000000000language: python python: - '2.7' - '3.4' - '3.5' - '3.6' - '3.7' - '3.8' install: - if [[ $TRAVIS_PYTHON_VERSION == 3.8 ]]; then pip install flake8; fi - pip install . script: - if [[ $TRAVIS_PYTHON_VERSION == 3.8 ]]; then flake8 .; fi - py.test deploy: provider: pypi user: herrkaste password: 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= on: tags: true python: 3.8 branch: master distributions: sdist bdist_wheel repo: kaste/mockito-python mockito-python-1.2.2/AUTHORS000066400000000000000000000000721372607637100155630ustar00rootroot00000000000000Szczepan Faber Serhiy Oplakanets Herr Kaste Justin Hopper mockito-python-1.2.2/CHANGES.txt000066400000000000000000000201171372607637100163260ustar00rootroot00000000000000MOCKITO CHANGE LOG ================== Release 1.2.2 (September 9, 2020) --------------------------------- - Fix typo in ``spy2`` doc Release 1.2.1 (February 19, 2020) --------------------------------- - @nielsvaneck fixed how we can lookup inherited classmethods. Release 1.2.0 (November 25, 2019) --------------------------------- - Code base now is python 3 compatible. No 2to3 anymore. - 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')``. - @felixonmars fixed a small compatibility issue with python 3.8 - Mocking properties has become a bit easier. (#26) E.g. prop = mock() when(m).__get__(...).thenReturn(23) m = mock({'name': prop}) Release 1.1.1 (August 28, 2018) ------------------------------- - Fix: The context manager (``with``) has now a proper implementation - Fix: Calling ``patch`` with two arguments can now be used with ``with`` - 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.) - 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_!) Release 1.1.0 (May 2, 2018) --------------------------- - Added ``forget_invocations`` function. Thanks to @maximkulkin This is generally useful if you already call mocks during your setup routine. Now you could call ``forget_invocations`` at the end of your setup, and have a clean 'recording' for your actual test code. T.i. you don't have to count the invocations from your setup code anymore. Release 1.0.12 (June 3, 2017) ----------------------------- - Better error messages for failed verifications. By @lwoydziak Release 1.0.7 - 1.0.10 (January 31 - February 2, 2017) ------------------------------------------------------ - ``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. - ``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. - All `verify*` functions now warn you if you pass in an object which was never stubbed. Release 1.0.0 - 1.0.5 (January 24 - 27, 2017) --------------------------------------------- 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. 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`. 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 with your usage. Usually this should help you find bugs in your code, because it will make it easier to spot changing interfaces. - ``mock``, ``when``, ``verify`` return mostly empty objects. It is unlikely to have a method_name clash. - Specced mocks ``instance = mock(Class)`` will pass isinstance tests like ``isinstance(instance, Class)`` - 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. - Mocks can be preconfigured: ``mock({'text': 'OK'})``. For specced mocks this would be e.g. ``mock({'text': 'OK'}, spec=requests.Response)``. - If you mock or patch an object, the function signatures will be matched. So:: def foo(a, b=1): ... when(main).foo(12) # will pass when(main).foo(c=13) # will raise immediately - Mock Dummies are now callable:: m = mock() m(1, 2) verify(m).__call__(...) - ``Mock()`` is now an implementation detail; it is **not** exported anymore. Use ``mock()``. - You can unstub individual patched objects ``unstub(obj)``. (Before it was all or nothing.) - Added basic context manager support when using ``when``. Note that ``verify`` has to be called within the with context. :: with when(rex).waggle().thenReturn('Yup'): assert rex.waggle() == 'Yup' verify(rex).waggle() - Aliased ``any_`` to ``ANY``, ``args`` to ``ARGS`` and ``kwargs`` to ``KWARGS``. You can use python's builtin ``any`` as a stand in for ``ANY``. - As a convenience you can use our ``any_`` matcher like a type instead of ``any_()``:: dummy(1) verify(dummy).__call__(ANY) - Added ``when2``, ``expect``, ``spy2`` - Make the mocked function (replacement) more inspectable. Copy `__doc__`, `__name__` etc. - You can configure magic methods on mocks:: dummy = mock() when(dummy).__getitem__(1).thenReturn(2) assert dummy[1] == 2 Release 0.7.1 (December 27, 2016) --------------------------------- - Fix: Allow ``verifyNoMoreInteractions`` call for real (stubbed) objects Release 0.7.0 (July 15, 2016) ----------------------------- - Added a ton of new argument matchers. Namely:: 'and_', 'or_', 'not_', 'eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'arg_that', 'matches', 'captor' - Aliases ``any`` matcher to ``any_`` because it's a builtin. - 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:: m = mock() f = m.foo # detach f(1, 2) # pass it around and use it like a function f(2, 3) verify(m).foo(...) # finally verify interactions Thank you @maximkulkin Release 0.6.1 (May 20, 2016) ---------------------------- - 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:: m = mock() when(m).do_times(any(), any()).thenAnswer(lambda one, two: one * two) self.assertEquals(20, m.do_times(5, 4)) Thank you @stubbsd Release 0.6.0 (April 25, 2016) ------------------------------ - Print keyword arguments nicely. - Be very forgiving about return values and assume None as default. T.i. ``when(Dog).bark('Miau').thenReturn()`` is enough to return None. - Make keyword argument order unimportant. - BREAKING CHANGE: Throw early when calling not expected methods in strict mode. Release 0.5.3 (April 23, 2016) ------------------------------ - Remove hard coded distribute setup files. Release 0.5.1 (August 4, 2010) ------------------------------ BUG Fixes: - Fixed issue #9 [http://bitbucket.org/szczepiq/mockito-python/issue/9] : Generating stubs from classes caused method to be replaced in original classes. Release 0.5.0 (July 26, 2010) ----------------------------- API Changes: - Added possibility to spy on real objects. - Added "never" syntactic sugar for verifications. BUG Fixes: - Fixed issue with named arguments matching. Other Changes: - Python 2.7 support - Deprecated APIs now generate deprecation warnings. Release 0.4.0 (July 2, 2010) ---------------------------- API Changes: - Added possibility to verify invocations in order. BUG Fixes: - Fixed issue with installing mockito from egg without distribute installed. Release 0.3.1 ------------- Bug-fix release. Bug Fixes: - Fixed annoying issue #8 [http://bitbucket.org/szczepiq/mockito-python/issue/8] Release 0.3.0 ------------- API Changes: - Renamed mock creation method from "Mock" (upper "M") to "mock". Old name stays for compatibility until 1.0 release. Other Changes: - Official Python3 support via distutils + 2to3. mockito-python-1.2.2/LICENSE000066400000000000000000000021311372607637100155160ustar00rootroot00000000000000Copyright (c) 2008-2019 Szczepan Faber, Serhiy Oplakanets, Herr Kaste Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mockito-python-1.2.2/MANIFEST.in000066400000000000000000000001371372607637100162530ustar00rootroot00000000000000include AUTHORS include CHANGES.txt include LICENSE include README.rst global-exclude *.py[co]mockito-python-1.2.2/README.rst000066400000000000000000000016571372607637100162140ustar00rootroot00000000000000Mockito is a spying framework originally based on `the Java library with the same name `_. .. image:: https://travis-ci.org/kaste/mockito-python.svg?branch=master :target: https://travis-ci.org/kaste/mockito-python Install ======= ``pip install mockito`` Quick Start =========== 90% use case is that you want to stub out a side effect. :: from mockito import when, mock, unstub when(os.path).exists('/foo').thenReturn(True) # or: import requests # the famous library # you actually want to return a Response-like obj, we'll fake it response = mock({'status_code': 200, 'text': 'Ok'}) when(requests).get(...).thenReturn(response) # use it requests.get('http://google.com/') # clean up unstub() Read the docs ============= http://mockito-python.readthedocs.io/en/latest/ Run the tests ------------- :: pip install pytest py.test mockito-python-1.2.2/bump.bat000066400000000000000000000001331372607637100161440ustar00rootroot00000000000000bump2version release --tag bump2version patch --no-tag --message "master is {new_version}" mockito-python-1.2.2/docs/000077500000000000000000000000001372607637100154445ustar00rootroot00000000000000mockito-python-1.2.2/docs/Makefile000066400000000000000000000176401372607637100171140ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(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/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " epub3 to make an epub3" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" @echo " dummy to check syntax errors of document sources" .PHONY: clean clean: rm -rf $(BUILDDIR)/* .PHONY: html html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." .PHONY: dirhtml dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." .PHONY: singlehtml singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." .PHONY: pickle pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." .PHONY: json json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." .PHONY: htmlhelp htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." .PHONY: qthelp qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mockito-python.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mockito-python.qhc" .PHONY: applehelp applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." .PHONY: devhelp devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/mockito-python" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mockito-python" @echo "# devhelp" .PHONY: epub epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." .PHONY: epub3 epub3: $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 @echo @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." .PHONY: latex latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." .PHONY: latexpdf latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: latexpdfja latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." .PHONY: text text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." .PHONY: man man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." .PHONY: texinfo texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." .PHONY: info info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." .PHONY: gettext gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." .PHONY: changes changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." .PHONY: linkcheck linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." .PHONY: doctest doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." .PHONY: coverage coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." .PHONY: xml xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." .PHONY: pseudoxml pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." .PHONY: dummy dummy: $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy @echo @echo "Build finished. Dummy builder generates no files." mockito-python-1.2.2/docs/_static/000077500000000000000000000000001372607637100170725ustar00rootroot00000000000000mockito-python-1.2.2/docs/_static/alabaster.css000066400000000000000000000250261372607637100215470ustar00rootroot00000000000000 @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; font-size: 17px; background-color: #fff; color: #000; margin: 0; padding: 0; } div.document { width: 940px; margin: 30px auto 0 auto; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 220px; } div.sphinxsidebar { width: 220px; font-size: 14px; line-height: 1.5; } hr { border: 1px solid #B1B4B6; } div.body { background-color: #fff; color: #3E4349; padding: 0 30px 0 30px; } div.body > .section { text-align: left; } div.footer { width: 940px; margin: 20px auto 30px auto; font-size: 14px; color: #888; text-align: right; } div.footer a { color: #888; } p.caption { font-family: inherit; font-size: inherit; } div.relations { display: none; } div.sphinxsidebar a { color: #444; text-decoration: none; border-bottom: 1px dotted #999; } div.sphinxsidebar a:hover { border-bottom: 1px solid #999; } div.sphinxsidebarwrapper { padding: 18px 10px; } div.sphinxsidebarwrapper p.logo { padding: 0; margin: -10px 0 0 0px; text-align: center; } div.sphinxsidebarwrapper h1.logo { margin-top: -10px; text-align: center; margin-bottom: 5px; text-align: left; } div.sphinxsidebarwrapper h1.logo-name { margin-top: 0px; } div.sphinxsidebarwrapper p.blurb { margin-top: 0; font-style: normal; } div.sphinxsidebar h3, div.sphinxsidebar h4 { font-family: 'Garamond', 'Georgia', serif; color: #444; font-size: 24px; font-weight: normal; margin: 0 0 5px 0; padding: 0; } div.sphinxsidebar h4 { font-size: 20px; } div.sphinxsidebar h3 a { color: #444; } div.sphinxsidebar p.logo a, div.sphinxsidebar h3 a, div.sphinxsidebar p.logo a:hover, div.sphinxsidebar h3 a:hover { border: none; } div.sphinxsidebar p { color: #555; margin: 10px 0; } div.sphinxsidebar ul { margin: 10px 0; padding: 0; color: #000; } div.sphinxsidebar ul li.toctree-l1 > a { font-size: 120%; } div.sphinxsidebar ul li.toctree-l2 > a { font-size: 110%; } div.sphinxsidebar input { border: 1px solid #CCC; font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; font-size: 1em; } div.sphinxsidebar hr { border: none; height: 1px; color: #AAA; background: #AAA; text-align: left; margin-left: 0; width: 50%; } /* -- body styles ----------------------------------------------------------- */ a { color: #004B6B; text-decoration: underline; } a:hover { color: #6D4100; text-decoration: underline; } div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; margin: 30px 0px 10px 0px; padding: 0; } div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } div.body h2 { font-size: 180%; } div.body h3 { font-size: 150%; } div.body h4 { font-size: 130%; } div.body h5 { font-size: 100%; } div.body h6 { font-size: 100%; } a.headerlink { color: #DDD; padding: 0 4px; text-decoration: none; } a.headerlink:hover { color: #444; background: #EAEAEA; } div.body p, div.body dd, div.body li { line-height: 1.4em; } div.admonition { margin: 20px 0px; padding: 10px 30px; background-color: #EEE; border: 1px solid #CCC; } div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { background-color: ; border-bottom: 1px solid #fafafa; } dd div.admonition { /* margin-left: -60px; padding-left: 60px; */} div.admonition p.admonition-title { font-family: 'Garamond', 'Georgia', serif; font-weight: normal; font-size: 18px; margin: 0 0 10px 0; padding: 0; /*line-height: 1;*/ } div.admonition p.last { margin-bottom: 0; } div.highlight { background-color: #fff; } dt:target, .highlight { background: #FAF3E8; } div.warning { background-color: #FCC; border: 1px solid #FAA; } div.danger { background-color: #FCC; border: 1px solid #FAA; -moz-box-shadow: 2px 2px 4px #D52C2C; -webkit-box-shadow: 2px 2px 4px #D52C2C; box-shadow: 2px 2px 4px #D52C2C; } div.error { background-color: #FCC; border: 1px solid #FAA; -moz-box-shadow: 2px 2px 4px #D52C2C; -webkit-box-shadow: 2px 2px 4px #D52C2C; box-shadow: 2px 2px 4px #D52C2C; } div.caution { background-color: #FCC; border: 1px solid #FAA; } div.attention { background-color: #FCC; border: 1px solid #FAA; } div.important { background-color: #EEE; border: 1px solid #CCC; } div.note { background-color: #EEE; border: 1px solid #CCC; } div.tip { background-color: #EEE; border: 1px solid #CCC; } div.hint { background-color: #EEE; border: 1px solid #CCC; } div.seealso { background-color: #EEE; border: 1px solid #CCC; } div.topic { background-color: #EEE; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre, tt, code { font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.9em; } .hll { background-color: #FFC; margin: 0 -12px; padding: 0 12px; display: block; } img.screenshot { } tt.descname, tt.descclassname, code.descname, code.descclassname { font-size: 0.95em; } tt.descname, code.descname { padding-right: 0.08em; } img.screenshot { -moz-box-shadow: 2px 2px 4px #EEE; -webkit-box-shadow: 2px 2px 4px #EEE; box-shadow: 2px 2px 4px #EEE; } table.docutils { border: 1px solid #888; -moz-box-shadow: 2px 2px 4px #EEE; -webkit-box-shadow: 2px 2px 4px #EEE; box-shadow: 2px 2px 4px #EEE; } table.docutils td, table.docutils th { border: 1px solid #888; padding: 0.25em 0.7em; } table.field-list, table.footnote { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } table.footnote { margin: 15px 0; width: 100%; border: 1px solid #EEE; background: #FDFDFD; font-size: 0.9em; } table.footnote + table.footnote { margin-top: -15px; border-top: none; } table.field-list th { padding: 0 0.8em 0 0; } table.field-list td { padding: 0; } table.field-list p { margin-bottom: 0.8em; } table.footnote td.label { width: .1px; padding: 0.3em 0 0.3em 0.5em; } table.footnote td { padding: 0.3em 0.5em; } dl { margin: 0; padding: 0; } dl dd { margin-left: 30px; } blockquote { margin: 0 0 0 30px; padding: 0; } ul, ol { /* Matches the 30px from the narrow-screen "li > ul" selector below */ margin: 10px 0 10px 30px; padding: 0; } pre { background: #EEE; padding: 7px 30px; margin: 15px 0px; line-height: 1.3em; } div.viewcode-block:target { background: #ffd; } dl pre, blockquote pre, li pre { margin-left: 0; padding-left: 30px; } dl dl pre { margin-left: -90px; padding-left: 90px; } tt, code { background-color: #ecf0f3; color: #222; /* padding: 1px 2px; */ } tt.xref, code.xref, a tt { background-color: #FBFBFB; border-bottom: 1px solid #fff; } a.reference { text-decoration: none; border-bottom: 1px dotted #004B6B; } /* Don't put an underline on images */ a.image-reference, a.image-reference:hover { border-bottom: none; } a.reference:hover { border-bottom: 1px solid #6D4100; } a.footnote-reference { text-decoration: none; font-size: 0.7em; vertical-align: top; border-bottom: 1px dotted #004B6B; } a.footnote-reference:hover { border-bottom: 1px solid #6D4100; } a:hover tt, a:hover code { background: #EEE; } @media screen and (max-width: 870px) { div.sphinxsidebar { display: none; } div.document { width: 100%; } div.documentwrapper { margin-left: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; } div.bodywrapper { margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0; } ul { margin-left: 0; } li > ul { /* Matches the 30px from the "ul, ol" selector above */ margin-left: 30px; } .document { width: auto; } .footer { width: auto; } .bodywrapper { margin: 0; } .footer { width: auto; } .github { display: none; } } @media screen and (max-width: 875px) { body { margin: 0; padding: 20px 30px; } div.documentwrapper { float: none; background: #fff; } div.sphinxsidebar { display: block; float: none; width: 102.5%; margin: 50px -30px -20px -30px; padding: 10px 20px; background: #333; color: #FFF; } div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, div.sphinxsidebar h3 a { color: #fff; } div.sphinxsidebar a { color: #AAA; } div.sphinxsidebar p.logo { display: none; } div.document { width: 100%; margin: 0; } div.footer { display: none; } div.bodywrapper { margin: 0; } div.body { min-height: 0; padding: 0; } .rtd_doc_footer { display: none; } .document { width: auto; } .footer { width: auto; } .footer { width: auto; } .github { display: none; } } /* misc. */ .revsys-inline { display: none!important; } /* Make nested-list/multi-paragraph items look better in Releases changelog * pages. Without this, docutils' magical list fuckery causes inconsistent * formatting between different release sub-lists. */ div#changelog > div.section > ul > li > p:only-child { margin-bottom: 0; } /* Hide fugly table cell borders in ..bibliography:: directive output */ table.docutils.citation, table.docutils.citation td, table.docutils.citation th { border: none; /* Below needed in some edge cases; if not applied, bottom shadows appear */ -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } code { background-color: #eee; } code span.pre { padding: 0px 4px; } dl { margin: 3em 0; } div.note { background-color: #dceef3; border: 1px solid #85aabf; } dt:target, .highlighted { background-color: #fbe54e; }mockito-python-1.2.2/docs/changes.rst000066400000000000000000000000331372607637100176020ustar00rootroot00000000000000.. include:: ../CHANGES.txtmockito-python-1.2.2/docs/conf.py000066400000000000000000000235761372607637100167600ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # mockito-python documentation build configuration file, created by # sphinx-quickstart on Tue Apr 26 14:00:19 2016. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os import pkg_resources # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.todo', # 'sphinx.ext.githubpages', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'mockito-python' copyright = u'2016, Szczepan Faber, Serhiy Oplakanets, herr.kaste' author = u'Szczepan Faber, Serhiy Oplakanets, herr.kaste' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. # version = u'0.6' # The full version, including alpha/beta/rc tags. # release = u'0.6.1' try: release = pkg_resources.get_distribution('mockito').version except pkg_resources.DistributionNotFound: print('mockito must be installed to build the documentation.') print('Install from source using `pip install -e .` in a virtualenv.') sys.exit(1) if 'dev' in release: release = ''.join(release.partition('dev')[:2]) version = '.'.join(release.split('.')[:2]) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. #html_title = u'mockito-python v0.6.1' # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. #html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} html_sidebars = { '**': ['localtoc.html', 'relations.html', 'searchbox.html'], } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' #html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. #html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = 'mockito-pythondoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Latex figure (float) alignment #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'mockito-python.tex', u'mockito-python Documentation', u'Szczepan Faber, Serhiy Oplakanets, herr.kaste', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'mockito-python', u'mockito-python Documentation', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'mockito-python', u'mockito-python Documentation', author, 'mockito-python', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False mockito-python-1.2.2/docs/index.rst000066400000000000000000000051041372607637100173050ustar00rootroot00000000000000.. mockito-python documentation master file, created by sphinx-quickstart on Tue Apr 26 14:00:19 2016. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. .. module:: mockito Mockito is a spying framework originally based on the Java library with the same name. .. image:: https://travis-ci.org/kaste/mockito-python.svg?branch=master :target: https://travis-ci.org/kaste/mockito-python Install ------- .. code-block:: python pip install mockito If you already use `pytest`, consider using the plugin `pytest-mockito `_. Use --- .. code-block:: python from mockito import when, mock, unstub when(os.path).exists('/foo').thenReturn(True) # or: import requests # the famous library # you actually want to return a Response-like obj, we'll fake it response = mock({'status_code': 200, 'text': 'Ok'}) when(requests).get(...).thenReturn(response) # use it requests.get('http://google.com/') # clean up unstub() Features -------- Super easy to set up different answers. :: # Well, you know the internet when(requests).get(...).thenReturn(mock({'status': 501})) \ .thenRaise(Timeout("I'm flaky")) \ .thenReturn(mock({'status': 200, 'text': 'Ok'})) State-of-the-art, high-five argument matchers:: # Use the Ellipsis, if you don't care when(deferred).defer(...).thenRaise(Timeout) # Or **kwargs from mockito import kwargs # or KWARGS when(requests).get('http://my-api.com/user', **kwargs) # The usual matchers from mockito import ANY, or_, not_ number = or_(ANY(int), ANY(float)) when(math).sqrt(not_(number)).thenRaise( TypeError('argument must be a number')) No need to `verify` (`assert_called_with`) all the time:: # Different arguments, different answers when(foo).bar(1).thenReturn(2) when(foo).bar(2).thenReturn(3) # but: foo.bar(3) # throws immediately: unexpected invocation # because of that you just know that when # you get a `2`, you called it with `1` Signature checking:: # when stubbing when(requests).get() # throws immediately: TypeError url required # when calling request.get(location='http://example.com/') # TypeError Read ---- .. toctree:: :maxdepth: 1 walk-through recipes the-functions the-matchers Changelog Report issues, contribute more documentation or give feedback at `Github `_! mockito-python-1.2.2/docs/make.bat000066400000000000000000000164531372607637100170620ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. epub3 to make an epub3 echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled echo. dummy to check syntax errors of document sources goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 1>NUL 2>NUL if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\mockito-python.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\mockito-python.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "epub3" ( %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) if "%1" == "dummy" ( %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy if errorlevel 1 exit /b 1 echo. echo.Build finished. Dummy builder generates no files. goto end ) :end mockito-python-1.2.2/docs/nutshell.rst000066400000000000000000000063011372607637100200340ustar00rootroot00000000000000TL;DR ----- :: >>> from mockito import * >>> myMock = mock() >>> when(myMock).getStuff().thenReturn('stuff') >>> myMock.getStuff() 'stuff' >>> verify(myMock).getStuff() >>> when(myMock).doSomething().thenRaise(Exception('Did a bad thing')) >>> myMock.doSomething() Traceback (most recent call last): <...> Exception: Did a bad thing No difference whatsoever when you mock modules :: >>> import os.path >>> when(os.path).exists('somewhere/somewhat').thenReturn(True) >>> when(os.path).exists('somewhere/something').thenReturn(False) >>> os.path.exists('somewhere/somewhat') True >>> os.path.exists('somewhere/something') False >>> os.path.exists('another_place') Traceback (most recent call last): <...> mockito.invocation.InvocationError: You called exists with ('another_place',) as arguments but we did not expect that. >>> when(os.path).exist('./somewhat').thenReturn(True) Traceback (most recent call last): <...> mockito.invocation.InvocationError: You tried to stub a method 'exist' the objec t () doesn't have. If that's too strict, you can change it :: >>> when(os.path, strict=False).exist('another_place').thenReturn('well, nice he re') >>> os.path.exist('another_place') 'well, nice here' >>> os.path.exist('and here?') >>> No surprise, you can do the same with your classes :: >>> class Dog(object): ... def bark(self): ... return "Wau" ... >>> when(Dog).bark().thenReturn('Miau!') >>> rex = Dog() >>> rex.bark() 'Miau!' or just with instances, first unstub :: >>> unstub() >>> rex.bark() 'Wau' then do :: >>> when(rex).bark().thenReturn('Grrrrr').thenReturn('Wuff') and get something different on consecutive calls :: >>> rex.bark() 'Grrrrr' >>> rex.bark() 'Wuff' >>> rex.bark() 'Wuff' and since you stubbed an instance, a different instance will not be stubbed :: >>> bello = Dog() >>> bello.bark() 'Wau' You have 4 modifiers when verifying :: >>> verify(rex, times=3).bark() >>> verify(rex, atleast=1).bark() >>> verify(rex, atmost=3).bark() >>> verify(rex, between=[1,3]).bark() >>> Finally, we have two matchers :: >>> myMock = mock() >>> when(myMock).do(any(int)).thenReturn('A number') >>> when(myMock).do(any(str)).thenReturn('A string') >>> myMock.do(2) 'A number' >>> myMock.do('times') 'A string' >>> verify(myMock).do(any(int)) >>> verify(myMock).do(any(str)) >>> verify(myMock).do(contains('time')) >>> exit() .. toctree:: :maxdepth: 2 mockito-python-1.2.2/docs/recipes.rst000066400000000000000000000045541372607637100176400ustar00rootroot00000000000000.. module:: mockito Recipes ======= Classes as factories -------------------- We want to test the following code:: import requests def fetch(url): session = requests.Session() return session.get(url) In a traditional sense this code is not designed for *testability*. But we don't care here. 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:: from mockito import when, mock, verifyStubbedInvocationsAreUsed def test_fetch(unstub): url = 'http://example.com/' response = mock({'text': 'Ok'}, spec=requests.Response) # remember: `mock` here just creates an empty object specced after # requests.Session session = mock(requests.Session) # `when` here configures the mock when(session).get(url).thenReturn(response) # `when` *patches* the globally available *requests* module when(requests).Session().thenReturn(session) # <= res = fetch(url) assert res.text == 'Ok' # no need to verify anything here, if we get the expected response # back, `url` must have been passed through the system, otherwise # mockito would have thrown. # We *could* ensure that our mocks are actually used, if we want: verifyStubbedInvocationsAreUsed() Faking magic methods -------------------- We want to test the following code:: import requests def fetch_2(url): with requests.Session() as session: return session.get(url) It's basically the same problem, but we need to add support for the context manager, the `with` interface:: from mockito import when, mock, args def test_fetch_with(unstub): url = 'http://example.com/' response = mock({'text': 'Ok'}, spec=requests.Response) session = mock(requests.Session) when(session).get(url).thenReturn(response) when(session).__enter__().thenReturn(session) # <= when(session).__exit__(*args) # <= when(requests).Session().thenReturn(session) res = fetch_2(url) assert res.text == 'Ok' mockito-python-1.2.2/docs/the-functions.rst000066400000000000000000000015631372607637100207710ustar00rootroot00000000000000.. module:: mockito The functions ============= 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` .. autofunction:: when .. autofunction:: when2 .. autofunction:: patch .. autofunction:: expect .. autofunction:: mock .. autofunction:: unstub .. autofunction:: forget_invocations .. autofunction:: spy .. autofunction:: spy2 This looks like a plethora of verification functions, and especially since you often don't need to `verify` at all. .. autofunction:: verify .. autofunction:: verifyNoMoreInteractions .. autofunction:: verifyZeroInteractions .. autofunction:: verifyNoUnwantedInteractions .. autofunction:: verifyStubbedInvocationsAreUsed mockito-python-1.2.2/docs/the-matchers.rst000066400000000000000000000001121372607637100205540ustar00rootroot00000000000000The matchers ============ .. automodule:: mockito.matchers :members: mockito-python-1.2.2/docs/walk-through.rst000066400000000000000000000164421372607637100206210ustar00rootroot00000000000000The Walk-through ================ The 90% use case is that want to stub out a side effect. This is also known as (monkey-)patching. With mockito, it's:: from mockito import when # stub `os.path.exists` when(os.path).exists('/foo').thenReturn(True) os.path.exists('/foo') # => True os.path.exists('/bar') # -> throws unexpected invocation 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. There are of course reasons when you don't want to overspecify specific tests. You _just_ want the desired stub answer. Here we go:: when(os.path).exists(...).thenReturn(True) # now, obviously, you get the same answer, regardless of the arguments os.path.exists('FooBar') # => True You can combine both stubs. E.g. nothing exists, except one file:: when(os.path).exists(...).thenReturn(False) when(os.path).exists('.flake8').thenReturn(True) And because it's a similar pattern, we can introduce :func:`spy2` here. Spies call through the original implementation of a given function. E.g. everything is as it is, except `'.flake8'` is just not there:: from mockito import spy2 spy2(os.path.exists) when(os.path).exists('.flake8').thenReturn(False) When patching, you **MUST** **not** forget to :func:`unstub` of course! You can do this explicitly :: from mockito import unstub unstub() # restore os.path module Usually you do this unconditionally in your `teardown` function. If you're using `pytest`, you could define a fixture instead :: # conftest.py import pytest @pytest.fixture def unstub(): from mockito import unstub yield unstub() # my_test.py import pytest pytestmark = pytest.mark.usefixtures("unstub") But very often you just use context managers (aka `with`), and mockito will unstub on 'exit' automatically:: # E.g. test that `exists` gets never called with expect(os.path, times=0).exists('.flake8'): # within the block `os.path.exists` is patched cached_dir_lookup('.flake8') # at the end of the block `os.path` gets unpatched # Which is btw roughly the same as doing with when(os.path).exists('.flake8'): cached_dir_lookup('.flake8') verify(os.path, times=0).exists(...) Now let's mix global module patching with mocks. We want to test the following function using the fab `requests` library:: import requests def get_text(url): res = requests.get(url) if 200 <= res.status_code < 300: return res.text return None How, dare, we did not inject our dependencies! Obviously we can get over that by patching at the module level like before:: when(requests).get('https://example.com/api').thenReturn(...) 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? Should we actually use a 'real' response object? No, we fake it using :func:`mock`. :: # setup response = mock({ 'status_code': 200, 'text': 'Ok' }, spec=requests.Response) when(requests).get('https://example.com/api').thenReturn(response) # run assert get_text('https://example.com/api') == 'Ok' # done! Say you want to mock the class Dog:: class Dog(object): def bark(self): return 'Wuff' # either mock the class when(Dog).bark().thenReturn('Miau!') # now all instances have a different behavior rex = Dog() assert rex.bark() == 'Miau!' # or mock a concrete instance when(rex).bark().thenReturn('Grrrr') assert rex.bark() == 'Grrrr' # a different dog will still 'Miau!' assert Dog().bark() == 'Miau!' # be sure to call unstub() once in while unstub() Sure, you can verify your interactions:: from mockito import verify # once again rex = Dog() when(rex).bark().thenReturn('Grrrr') rex.bark() rex.bark() # `times` defaults to 1 verify(rex, times=2).bark() In general mockito is very picky:: # this will fail because `Dog` has no method named `waggle` when(rex).waggle().thenReturn('Nope') # this will fail because `bark` does not take any arguments when(rex).bark('Grrr').thenReturn('Nope') # given this function def bark(sound, post='!'): return sound + post from mockito import kwargs when(main).bark('Grrr', **kwargs).thenReturn('Nope') # now this one will fail bark('Grrr') # because there are no keyword arguments used # this one will fail because `then` does not match the function signature bark('Grrr', then='!!') # this one will go bark('Grrr', post='?') # there is also an args matcher def add_tasks(*tasks, verbose=False): pass from mockito import args # If you omit the `thenReturn` it will just return `None` when(main).add_tasks(*args) add_tasks('task1', 'task2') # will go add_tasks() # will fail add_tasks('task1', verbose=True) # will fail too # On Python 3 you can also use `...` when(main).add_tasks(...) # when(main).add_tasks(Ellipsis) on Python 2 add_tasks('task1') # will go add_tasks(verbose=True) # will go add_tasks('task1', verbose=True) # will go add_tasks() # will go To start with an empty stub use :func:`mock`:: from mockito import mock obj = mock() # pass it around, eventually it will be used obj.say('Hi') # back in the tests, verify the interactions verify(obj).say('Hi') # by default all invoked methods take any arguments and return None # you can configure your expected method calls with the ususal `when` when(obj).say('Hi').thenReturn('Ho') # There is also a shortcut to set some attributes obj = mock({ 'hi': 'ho' }) assert obj.hi == 'ho' # This would work for methods as well; in this case obj = mock({ 'say': lambda _: 'Ho' }) # But you don't have any argument and signature matching assert obj.say('Anything') == 'Ho' # At least you can verify your calls verify(obj).say(...) # Btw, you can make screaming strict mocks:: obj = mock(strict=True) # every unconfigured, unexpected call will raise You can use an empty stub specced against a concrete class:: # Given the above `Dog` rex = mock(Dog) # Now you can stub out any known method on `Dog` but other will throw when(rex).bark().thenReturn('Miau') # this one will fail when(rex).waggle() # These mocks are in general very strict, so even this will fail rex.health # unconfigured attribute # Of course you can just set it in a setup routine rex.health = 121 # Or again preconfigure rex = mock({'health': 121}, spec=Dog) # preconfigure stubbed method rex = mock({'bark': lambda sound: 'Miau'}, spec=Dog) # as you specced the mock, you get at least function signature matching # `bark` does not take any arguments so rex.bark('sound') # will throw TypeError # Btw, you can make loose specced mocks:: rex = mock(Dog, strict=False) mockito-python-1.2.2/mockito/000077500000000000000000000000001372607637100161615ustar00rootroot00000000000000mockito-python-1.2.2/mockito/__init__.py000066400000000000000000000041741372607637100203000ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. '''Mockito is a Test Spy framework.''' from .mockito import ( when, when2, patch, expect, unstub, forget_invocations, verify, verifyNoMoreInteractions, verifyZeroInteractions, verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed, ArgumentError, ) from . import inorder from .spying import spy, spy2 from .mocking import mock from .verification import VerificationError from .matchers import * # noqa: F401 F403 from .matchers import any, contains, times from .verification import never __version__ = '1.2.2' __all__ = [ 'mock', 'spy', 'spy2', 'when', 'when2', 'patch', 'expect', 'verify', 'verifyNoMoreInteractions', 'verifyZeroInteractions', 'verifyNoUnwantedInteractions', 'verifyStubbedInvocationsAreUsed', 'inorder', 'unstub', 'forget_invocations', 'VerificationError', 'ArgumentError', 'any', # compatibility 'contains', # compatibility 'never', # compatibility 'times', # deprecated ] mockito-python-1.2.2/mockito/inorder.py000066400000000000000000000024121372607637100201740ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from .mockito import verify as verify_main def verify(object, *args, **kwargs): kwargs['inorder'] = True return verify_main(object, *args, **kwargs) mockito-python-1.2.2/mockito/invocation.py000066400000000000000000000345331372607637100207140ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from . import matchers import operator from . import signature from . import verification as verificationModule from .utils import contains_strict from collections import deque import functools class InvocationError(AttributeError): pass __tracebackhide__ = operator.methodcaller( "errisinstance", (InvocationError, verificationModule.VerificationError) ) class Invocation(object): def __init__(self, mock, method_name): self.mock = mock self.method_name = method_name self.strict = mock.strict self.params = () self.named_params = {} def _remember_params(self, params, named_params): self.params = params self.named_params = named_params def __repr__(self): args = [repr(p) if p is not Ellipsis else '...' for p in self.params] kwargs = ["%s=%r" % (key, val) if key is not matchers.KWARGS_SENTINEL else '**kwargs' for key, val in self.named_params.items()] params = ", ".join(args + kwargs) return "%s(%s)" % (self.method_name, params) class RememberedInvocation(Invocation): def __init__(self, mock, method_name): super(RememberedInvocation, self).__init__(mock, method_name) self.verified = False self.verified_inorder = False def ensure_mocked_object_has_method(self, method_name): if not self.mock.has_method(method_name): raise InvocationError( "You tried to call a method '%s' the object (%s) doesn't " "have." % (method_name, self.mock.mocked_obj)) def ensure_signature_matches(self, method_name, args, kwargs): sig = self.mock.get_signature(method_name) if not sig: return signature.match_signature(sig, args, kwargs) def __call__(self, *params, **named_params): if self.strict: self.ensure_mocked_object_has_method(self.method_name) self.ensure_signature_matches( self.method_name, params, named_params) self._remember_params(params, named_params) self.mock.remember(self) for matching_invocation in self.mock.stubbed_invocations: if matching_invocation.matches(self): matching_invocation.should_answer(self) return matching_invocation.answer_first( *params, **named_params) if self.strict: stubbed_invocations = [ invoc for invoc in self.mock.stubbed_invocations if invoc.method_name == self.method_name ] raise InvocationError( """ Called but not expected: %s Stubbed invocations are: %s """ % ( self, "\n ".join( str(invoc) for invoc in reversed(stubbed_invocations) ) ) ) return None class RememberedProxyInvocation(Invocation): '''Remeber params and proxy to method of original object. Calls method on original object and returns it's return value. ''' def __init__(self, mock, method_name): super(RememberedProxyInvocation, self).__init__(mock, method_name) self.verified = False self.verified_inorder = False def __call__(self, *params, **named_params): self._remember_params(params, named_params) self.mock.remember(self) obj = self.mock.spec try: method = getattr(obj, self.method_name) except AttributeError: raise AttributeError( "You tried to call method '%s' which '%s' instance does not " "have." % (self.method_name, obj)) return method(*params, **named_params) class MatchingInvocation(Invocation): @staticmethod def compare(p1, p2): if isinstance(p1, matchers.Matcher): if not p1.matches(p2): return False elif p1 != p2: return False return True def _remember_params(self, params, named_params): if ( contains_strict(params, Ellipsis) and (params[-1] is not Ellipsis or named_params) ): raise TypeError('Ellipsis must be the last argument you specify.') if contains_strict(params, matchers.args): raise TypeError('args must be used as *args') if ( contains_strict(params, matchers.kwargs) or contains_strict(params, matchers.KWARGS_SENTINEL) ): raise TypeError('kwargs must be used as **kwargs') def wrap(p): if p is any or p is matchers.any_: return matchers.any_() return p self.params = tuple(wrap(p) for p in params) self.named_params = {k: wrap(v) for k, v in named_params.items()} # Note: matches(a, b) does not imply matches(b, a) because # the left side might contain wildcards (like Ellipsis) or matchers. # In its current form the right side is a concrete call signature. def matches(self, invocation): # noqa: C901 (too complex) if self.method_name != invocation.method_name: return False for x, p1 in enumerate(self.params): # assume Ellipsis is the last thing a user declares if p1 is Ellipsis: return True if p1 is matchers.ARGS_SENTINEL: break try: p2 = invocation.params[x] except IndexError: return False if not self.compare(p1, p2): return False else: if len(self.params) != len(invocation.params): return False for key, p1 in sorted( self.named_params.items(), key=lambda k_v: 1 if k_v[0] is matchers.KWARGS_SENTINEL else 0 ): if key is matchers.KWARGS_SENTINEL: break try: p2 = invocation.named_params[key] except KeyError: return False if not self.compare(p1, p2): return False else: if len(self.named_params) != len(invocation.named_params): return False return True class VerifiableInvocation(MatchingInvocation): def __init__(self, mock, method_name, verification): super(VerifiableInvocation, self).__init__(mock, method_name) self.verification = verification def __call__(self, *params, **named_params): self._remember_params(params, named_params) matched_invocations = [] for invocation in self.mock.invocations: if self.matches(invocation): matched_invocations.append(invocation) self.verification.verify(self, len(matched_invocations)) # check (real) invocations as verified for invocation in matched_invocations: invocation.verified = True # check stubs as 'used' if verification_has_lower_bound_of_zero(self.verification): for stub in self.mock.stubbed_invocations: # Remember: matches(a, b) does not imply matches(b, a) # (see above!), so we check for both if stub.matches(self) or self.matches(stub): stub.allow_zero_invocations = True def verification_has_lower_bound_of_zero(verification): if ( isinstance(verification, verificationModule.Times) and verification.wanted_count == 0 ): return True if ( isinstance(verification, verificationModule.Between) and verification.wanted_from == 0 ): return True return False class StubbedInvocation(MatchingInvocation): def __init__(self, mock, method_name, verification=None, strict=None): super(StubbedInvocation, self).__init__(mock, method_name) #: Holds the verification set up via `expect`. #: The verification will be verified implicitly, while using this stub. self.verification = verification if strict is not None: self.strict = strict self.answers = CompositeAnswer() #: Counts how many times this stub has been 'used'. #: A stub gets used, when a real invocation matches its argument #: signature, and asks for an answer. self.used = 0 #: Set if `verifyStubbedInvocationsAreUsed` should pass, regardless #: of any factual invocation. E.g. set by `verify(..., times=0)` if verification_has_lower_bound_of_zero(verification): self.allow_zero_invocations = True else: self.allow_zero_invocations = False def ensure_mocked_object_has_method(self, method_name): if not self.mock.has_method(method_name): raise InvocationError( "You tried to stub a method '%s' the object (%s) doesn't " "have." % (method_name, self.mock.mocked_obj)) def ensure_signature_matches(self, method_name, args, kwargs): sig = self.mock.get_signature(method_name) if not sig: return signature.match_signature_allowing_placeholders(sig, args, kwargs) def __call__(self, *params, **named_params): if self.strict: self.ensure_mocked_object_has_method(self.method_name) self.ensure_signature_matches( self.method_name, params, named_params) self._remember_params(params, named_params) self.mock.stub(self.method_name) self.mock.finish_stubbing(self) return AnswerSelector(self) def forget_self(self): self.mock.forget_stubbed_invocation(self) def add_answer(self, answer): self.answers.add(answer) def answer_first(self, *args, **kwargs): self.used += 1 return self.answers.answer(*args, **kwargs) def should_answer(self, invocation): # type: (RememberedInvocation) -> None verification = self.verification if not verification: return # This check runs before `answer_first`. We add '1' because we want # to know if the verification passes if this call gets through. actual_count = self.used + 1 if isinstance(verification, verificationModule.Times): if actual_count > verification.wanted_count: raise InvocationError( "\nWanted times: %i, actual times: %i" % (verification.wanted_count, actual_count)) elif isinstance(verification, verificationModule.AtMost): if actual_count > verification.wanted_count: raise InvocationError( "\nWanted at most: %i, actual times: %i" % (verification.wanted_count, actual_count)) elif isinstance(verification, verificationModule.Between): if actual_count > verification.wanted_to: raise InvocationError( "\nWanted between: [%i, %i], actual times: %i" % (verification.wanted_from, verification.wanted_to, actual_count)) # The way mockito's `verify` works is, that it checks off all 'real', # remembered invocations, if they get verified. This is a simple # mechanism so that a later `verifyNoMoreInteractions` just has to # ensure that all invocations have this flag set to ``True``. # For verifications set up via `expect` we want all invocations # to get verified 'implicitly', on-the-go, so we set this flag here. invocation.verified = True def verify(self): if not self.verification: return actual_count = self.used self.verification.verify(self, actual_count) def return_(value, *a, **kw): return value def raise_(exception, *a, **kw): raise exception class AnswerSelector(object): def __init__(self, invocation): self.invocation = invocation def thenReturn(self, *return_values): for return_value in return_values: self.__then(functools.partial(return_, return_value)) return self def thenRaise(self, *exceptions): for exception in exceptions: self.__then(functools.partial(raise_, exception)) return self def thenAnswer(self, *callables): for callable in callables: self.__then(callable) return self def __then(self, answer): self.invocation.add_answer(answer) def __enter__(self): pass def __exit__(self, *exc_info): self.invocation.forget_self() class CompositeAnswer(object): def __init__(self): #: Container for answers, which are just ordinary callables self.answers = deque() #: Counter for the maximum answers we ever had self.answer_count = 0 def __len__(self): # The minimum is '1' bc we always have a default answer of 'None' return max(1, self.answer_count) def add(self, answer): self.answer_count += 1 self.answers.append(answer) def answer(self, *args, **kwargs): if len(self.answers) == 0: return None if len(self.answers) == 1: a = self.answers[0] else: a = self.answers.popleft() return a(*args, **kwargs) mockito-python-1.2.2/mockito/matchers.py000066400000000000000000000223241372607637100203440ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """Argument matchers for stubbing and verifications. In general the call signature you specify when stubbing or verifying in mockito is as concrete as possible: it consists of values only:: when(os.path).exists('/foo/bar.txt').thenReturn(True) This is for a reason. In controlled test environments, for the scope of a single test, you should usually know exactly how you use a function, and what you expect its outcome to be. In mockito usually (in `strict` mode) all invocations you did not specify upfront will throw at call time. If you reason about your code, the above `when` tirade turns - for the time of the test - the specific stubbed function into a constant. You can use so called argument matchers below if you can't or don't want to specify a single concrete value for an argument, but a type or class of possible values. E.g.:: when(os.path).exists(...).thenReturn(True) when(os.path).exists(ANY).thenReturn(True) when(os.path).exists(ANY(str)).thenReturn(True) when(requests).get(ANY(str), **kwargs) when(requests).get('https://example.com', ...) when(math).sqrt(not_(_or(ANY(float), ANY(int)))).thenRaise(TypeError) Now what you get each time is a function that up to a degree takes various arguments and responds with the same outcome each time. Now that's a weird thing. So use the matchers for a reason, they're powerful. The one usage you should not care about is a loose signature when using :func:`verify`. Since mockito will throw for unexpected calls, a very loose `verify` should be ok:: verify(requests, times=1).get(...) """ import re __all__ = [ 'and_', 'or_', 'not_', 'eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'any', 'any_', 'ANY', 'arg_that', 'contains', 'matches', 'captor', 'times', 'args', 'ARGS', 'kwargs', 'KWARGS' ] class _ArgsSentinel(object): def __repr__(self): return '*args' ARGS_SENTINEL = _ArgsSentinel() ARGS = args = [ARGS_SENTINEL] # ARGS.__doc__ = """Matches multiple positional arguments. # Note: `args` must match at least one argument. # Example:: # when(manager).add_tasks(1, 2, *args) # """ KWARGS_SENTINEL = '**' KWARGS = kwargs = {KWARGS_SENTINEL: '_'} # KWARGS.__doc__ = """Matches multiple keyword arguments. # Note that `kwargs` must match at least one remaining keyword argument. # Example:: # when(requests).get('http://myapi/', **KWARGS) # """ class Matcher: def matches(self, arg): pass class Any(Matcher): def __init__(self, wanted_type=None): self.wanted_type = wanted_type def matches(self, arg): if self.wanted_type: return isinstance(arg, self.wanted_type) else: return True def __repr__(self): return "" % self.wanted_type class ValueMatcher(Matcher): def __init__(self, value): self.value = value def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.value) class Eq(ValueMatcher): def matches(self, arg): return arg == self.value class Neq(ValueMatcher): def matches(self, arg): return arg != self.value class Lt(ValueMatcher): def matches(self, arg): return arg < self.value class Lte(ValueMatcher): def matches(self, arg): return arg <= self.value class Gt(ValueMatcher): def matches(self, arg): return arg > self.value class Gte(ValueMatcher): def matches(self, arg): return arg >= self.value class And(Matcher): def __init__(self, matchers): self.matchers = [ matcher if isinstance(matcher, Matcher) else Eq(matcher) for matcher in matchers] def matches(self, arg): return all(matcher.matches(arg) for matcher in self.matchers) def __repr__(self): return "" % self.matchers class Or(Matcher): def __init__(self, matchers): self.matchers = [ matcher if isinstance(matcher, Matcher) else Eq(matcher) for matcher in matchers] def matches(self, arg): return __builtins__['any']( [matcher.matches(arg) for matcher in self.matchers] ) def __repr__(self): return "" % self.matchers class Not(Matcher): def __init__(self, matcher): self.matcher = matcher if isinstance(matcher, Matcher) else Eq(matcher) def matches(self, arg): return not self.matcher.matches(arg) def __repr__(self): return "" % self.matcher class ArgThat(Matcher): def __init__(self, predicate): self.predicate = predicate def matches(self, arg): return self.predicate(arg) def __repr__(self): return "" class Contains(Matcher): def __init__(self, sub): self.sub = sub def matches(self, arg): if not hasattr(arg, 'find'): return return self.sub and len(self.sub) > 0 and arg.find(self.sub) > -1 def __repr__(self): return "" % self.sub class Matches(Matcher): def __init__(self, regex, flags=0): self.regex = re.compile(regex, flags) def matches(self, arg): if not isinstance(arg, str): return return self.regex.match(arg) is not None def __repr__(self): if self.regex.flags: return "" % (self.regex.pattern, self.regex.flags) else: return "" % self.regex.pattern class ArgumentCaptor(Matcher): def __init__(self, matcher=None): self.matcher = matcher or Any() self.value = None def matches(self, arg): result = self.matcher.matches(arg) if not result: return self.value = arg return True def __repr__(self): return "" % ( repr(self.matcher), self.value, ) def any(wanted_type=None): """Matches against type of argument (`isinstance`). If you want to match *any* type, use either `ANY` or `ANY()`. Examples:: when(mock).foo(any).thenReturn(1) verify(mock).foo(any(int)) """ return Any(wanted_type) ANY = any_ = any def eq(value): """Matches particular value (`==`)""" return Eq(value) def neq(value): """Matches any but given value (`!=`)""" return Neq(value) def lt(value): """Matches any value that is less than given value (`<`)""" return Lt(value) def lte(value): """Matches any value that is less than or equal to given value (`<=`)""" return Lte(value) def gt(value): """Matches any value that is greater than given value (`>`)""" return Gt(value) def gte(value): """Matches any value that is greater than or equal to given value (`>=`)""" return Gte(value) def and_(*matchers): """Matches if all given matchers match Example:: when(mock).foo(and_(ANY(str), contains('foo'))) """ return And(matchers) def or_(*matchers): """Matches if any given matcher match Example:: when(mock).foo(or_(ANY(int), ANY(float))) """ return Or(matchers) def not_(matcher): """Matches if given matcher does not match Example:: when(mock).foo(not_(ANY(str))).thenRaise(TypeError) """ return Not(matcher) def arg_that(predicate): """Matches any argument for which predicate returns True Example:: verify(mock).foo(arg_that(lambda arg: arg > 3 and arg < 7)) """ return ArgThat(predicate) def contains(sub): """Matches any string containing given substring Example:: mock.foo([120, 121, 122, 123]) verify(mock).foo(contains(123)) """ return Contains(sub) def matches(regex, flags=0): """Matches any string that matches given regex""" return Matches(regex, flags) def captor(matcher=None): """Returns argument captor that captures value for further assertions Example:: arg_captor = captor(any(int)) when(mock).do_something(arg_captor) mock.do_something(123) assert arg_captor.value == 123 """ return ArgumentCaptor(matcher) def times(count): return count mockito-python-1.2.2/mockito/mock_registry.py000066400000000000000000000053111372607637100214140ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. class MockRegistry: """Registry for mocks Registers mock()s, ensures that we only have one mock() per mocked_obj, and iterates over them to unstub each stubbed method. """ def __init__(self): self.mocks = _Dict() def register(self, obj, mock): self.mocks[obj] = mock def mock_for(self, obj): return self.mocks.get(obj, None) def unstub(self, obj): try: mock = self.mocks.pop(obj) except KeyError: pass else: mock.unstub() def unstub_all(self): for mock in self.get_registered_mocks(): mock.unstub() self.mocks.clear() def get_registered_mocks(self): return self.mocks.values() # We have this dict like because we want non-hashable items in our registry. # This is just enough to match the invoking code above. TBC class _Dict(object): def __init__(self): self._store = [] def __setitem__(self, key, value): self.remove(key) self._store.append((key, value)) def remove(self, key): self._store = [(k, v) for k, v in self._store if k != key] def pop(self, key): rv = self.get(key) if rv is not None: self.remove(key) return rv else: raise KeyError() def get(self, key, default=None): for k, value in self._store: if k == key: return value return default def values(self): return [v for k, v in self._store] def clear(self): self._store[:] = [] mock_registry = MockRegistry() mockito-python-1.2.2/mockito/mocking.py000066400000000000000000000245371372607637100201750ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import functools import inspect import operator from collections import deque from . import invocation, signature, utils from .mock_registry import mock_registry __all__ = ['mock'] __tracebackhide__ = operator.methodcaller( "errisinstance", invocation.InvocationError ) class _Dummy(object): # We spell out `__call__` here for convenience. All other magic methods # must be configured before use, but we want `mock`s to be callable by # default. def __call__(self, *args, **kwargs): return self.__getattr__('__call__')(*args, **kwargs) def remembered_invocation_builder(mock, method_name, *args, **kwargs): invoc = invocation.RememberedInvocation(mock, method_name) return invoc(*args, **kwargs) class Mock(object): def __init__(self, mocked_obj, strict=True, spec=None): self.mocked_obj = mocked_obj self.strict = strict self.spec = spec self.invocations = deque() self.stubbed_invocations = deque() self.original_methods = {} self._signatures_store = {} def remember(self, invocation): self.invocations.appendleft(invocation) def finish_stubbing(self, stubbed_invocation): self.stubbed_invocations.appendleft(stubbed_invocation) def clear_invocations(self): self.invocations = deque() # STUBBING def get_original_method(self, method_name): """ Looks up the original method on the `spec` object and returns it together with an indication of whether the method is found "directly" on the `spec` object. This is used to decide whether the method should be stored as an original_method and should therefore be replaced when unstubbing. """ if self.spec is None: return None, False try: return self.spec.__dict__[method_name], True except (AttributeError, KeyError): # Classes with defined `__slots__` and then no `__dict__` are not # patchable but if we catch the `AttributeError` here, we get # the better error message for the user. return getattr(self.spec, method_name, None), False def set_method(self, method_name, new_method): setattr(self.mocked_obj, method_name, new_method) def replace_method(self, method_name, original_method): def new_mocked_method(*args, **kwargs): # we throw away the first argument, if it's either self or cls if ( inspect.ismethod(new_mocked_method) or inspect.isclass(self.mocked_obj) and not isinstance(new_mocked_method, staticmethod) ): args = args[1:] return remembered_invocation_builder( self, method_name, *args, **kwargs) new_mocked_method.__name__ = method_name if original_method: new_mocked_method.__doc__ = original_method.__doc__ new_mocked_method.__wrapped__ = original_method try: new_mocked_method.__module__ = original_method.__module__ except AttributeError: pass if inspect.ismethod(original_method): new_mocked_method = utils.newmethod( new_mocked_method, self.mocked_obj ) if isinstance(original_method, staticmethod): new_mocked_method = staticmethod(new_mocked_method) elif isinstance(original_method, classmethod): new_mocked_method = classmethod(new_mocked_method) elif ( inspect.isclass(self.mocked_obj) and inspect.isclass(original_method) # TBC: Inner classes ): new_mocked_method = staticmethod(new_mocked_method) self.set_method(method_name, new_mocked_method) def stub(self, method_name): try: self.original_methods[method_name] except KeyError: original_method, was_in_spec = self.get_original_method( method_name) if was_in_spec: # This indicates the original method was found directly on # the spec object and should therefore be restored by unstub self.original_methods[method_name] = original_method else: self.original_methods[method_name] = None self.replace_method(method_name, original_method) def forget_stubbed_invocation(self, invocation): assert invocation in self.stubbed_invocations if len(self.stubbed_invocations) == 1: mock_registry.unstub(self.mocked_obj) return self.stubbed_invocations.remove(invocation) if not any( inv.method_name == invocation.method_name for inv in self.stubbed_invocations ): original_method = self.original_methods.pop(invocation.method_name) self.restore_method(invocation.method_name, original_method) def restore_method(self, method_name, original_method): # If original_method is None, we *added* it to mocked_obj, so we # must delete it here. # If we mocked an instance, our mocked function will actually hide # the one on its class, so we delete as well. if ( not original_method or not inspect.isclass(self.mocked_obj) and inspect.ismethod(original_method) ): delattr(self.mocked_obj, method_name) else: self.set_method(method_name, original_method) def unstub(self): while self.original_methods: method_name, original_method = self.original_methods.popitem() self.restore_method(method_name, original_method) # SPECCING def has_method(self, method_name): if self.spec is None: return True return hasattr(self.spec, method_name) def get_signature(self, method_name): if self.spec is None: return None try: return self._signatures_store[method_name] except KeyError: sig = signature.get_signature(self.spec, method_name) self._signatures_store[method_name] = sig return sig class _OMITTED(object): def __repr__(self): return 'OMITTED' OMITTED = _OMITTED() def mock(config_or_spec=None, spec=None, strict=OMITTED): """Create 'empty' objects ('Mocks'). Will create an empty unconfigured object, that you can pass around. All interactions (method calls) will be recorded and can be verified using :func:`verify` et.al. A plain `mock()` will be not `strict`, and thus all methods regardless of the arguments will return ``None``. .. note:: Technically all attributes will return an internal interface. Because of that a simple ``if mock().foo:`` will surprisingly pass. If you set strict to ``True``: ``mock(strict=True)`` all unexpected interactions will raise an error instead. You configure a mock using :func:`when`, :func:`when2` or :func:`expect`. You can also very conveniently just pass in a dict here:: response = mock({'text': 'ok', 'raise_for_status': lambda: None}) You can also create an empty Mock which is specced against a given `spec`: ``mock(requests.Response)``. These mock are by default strict, thus they raise if you want to stub a method, the spec does not implement. Mockito will also match the function signature. You can pre-configure a specced mock as well:: response = mock({'json': lambda: {'status': 'Ok'}}, spec=requests.Response) Mocks are by default callable. Configure the callable behavior using `when`:: dummy = mock() when(dummy).__call__(1).thenReturn(2) All other magic methods must be configured this way or they will raise an AttributeError. See :func:`verify` to verify your interactions after usage. """ if type(config_or_spec) is dict: config = config_or_spec else: config = {} spec = config_or_spec if strict is OMITTED: strict = False if spec is None else True class Dummy(_Dummy): if spec: __class__ = spec # make isinstance work def __getattr__(self, method_name): if strict: __tracebackhide__ = operator.methodcaller( "errisinstance", AttributeError ) raise AttributeError( "'Dummy' has no attribute %r configured" % method_name) return functools.partial( remembered_invocation_builder, theMock, method_name) def __repr__(self): name = 'Dummy' if spec: name += spec.__name__ return "<%s id=%s>" % (name, id(self)) # That's a tricky one: The object we will return is an *instance* of our # Dummy class, but the mock we register will point and patch the class. # T.i. so that magic methods (`__call__` etc.) can be configured. obj = Dummy() theMock = Mock(Dummy, strict=strict, spec=spec) for n, v in config.items(): if inspect.isfunction(v): invocation.StubbedInvocation(theMock, n)(Ellipsis).thenAnswer(v) else: setattr(Dummy, n, v) mock_registry.register(obj, theMock) return obj mockito-python-1.2.2/mockito/mockito.py000066400000000000000000000336111372607637100202040ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import operator from . import invocation from . import verification from .utils import get_obj, get_obj_attr_tuple from .mocking import Mock from .mock_registry import mock_registry from .verification import VerificationError class ArgumentError(Exception): pass __tracebackhide__ = operator.methodcaller( "errisinstance", (ArgumentError, VerificationError) ) def _multiple_arguments_in_use(*args): return len([x for x in args if x]) > 1 def _invalid_argument(value): return (value is not None and value < 1) or value == 0 def _invalid_between(between): if between is not None: try: start, end = between except Exception: return True if start > end or start < 0: return True return False def _get_wanted_verification( times=None, atleast=None, atmost=None, between=None): if times is not None and times < 0: raise ArgumentError("'times' argument has invalid value.\n" "It should be at least 0. You wanted to set it to:" " %i" % times) if _multiple_arguments_in_use(atleast, atmost, between): raise ArgumentError( "You can set only one of the arguments: 'atleast', " "'atmost' or 'between'.") if _invalid_argument(atleast): raise ArgumentError("'atleast' argument has invalid value.\n" "It should be at least 1. You wanted to set it " "to: %i" % atleast) if _invalid_argument(atmost): raise ArgumentError("'atmost' argument has invalid value.\n" "It should be at least 1. You wanted to set it " "to: %i" % atmost) if _invalid_between(between): raise ArgumentError( """'between' argument has invalid value. It should consist of positive values with second number not greater than first e.g. (1, 4) or (0, 3) or (2, 2). You wanted to set it to: %s""" % (between,)) if atleast: return verification.AtLeast(atleast) elif atmost: return verification.AtMost(atmost) elif between: return verification.Between(*between) elif times is not None: return verification.Times(times) def _get_mock(obj, strict=True): theMock = mock_registry.mock_for(obj) if theMock is None: theMock = Mock(obj, strict=strict, spec=obj) mock_registry.register(obj, theMock) return theMock def _get_mock_or_raise(obj): theMock = mock_registry.mock_for(obj) if theMock is None: raise ArgumentError("obj '%s' is not registered" % obj) return theMock def verify(obj, times=1, atleast=None, atmost=None, between=None, inorder=False): """Central interface to verify interactions. `verify` uses a fluent interface:: verify(, times=2).() `args` can be as concrete as necessary. Often a catch-all is enough, especially if you're working with strict mocks, bc they throw at call time on unwanted, unconfigured arguments:: from mockito import ANY, ARGS, KWARGS when(manager).add_tasks(1, 2, 3) ... # no need to duplicate the specification; every other argument pattern # would have raised anyway. verify(manager).add_tasks(1, 2, 3) # duplicates `when`call verify(manager).add_tasks(*ARGS) verify(manager).add_tasks(...) # Py3 verify(manager).add_tasks(Ellipsis) # Py2 """ if isinstance(obj, str): obj = get_obj(obj) verification_fn = _get_wanted_verification( times=times, atleast=atleast, atmost=atmost, between=between) if inorder: verification_fn = verification.InOrder(verification_fn) theMock = _get_mock_or_raise(obj) class Verify(object): def __getattr__(self, method_name): return invocation.VerifiableInvocation( theMock, method_name, verification_fn) return Verify() class _OMITTED(object): def __repr__(self): return 'OMITTED' OMITTED = _OMITTED() def when(obj, strict=True): """Central interface to stub functions on a given `obj` `obj` should be a module, a class or an instance of a class; it can be a Dummy you created with :func:`mock`. ``when`` exposes a fluent interface where you configure a stub in three steps:: when().().thenReturn() Compared to simple *patching*, stubbing in mockito requires you to specify conrete `args` for which the stub will answer with a concrete ``. All invocations that do not match this specific call signature will be rejected. They usually throw at call time. Stubbing in mockito's sense thus means not only to get rid of unwanted side effects, but effectively to turn function calls into constants. E.g.:: # Given ``dog`` is an instance of a ``Dog`` when(dog).bark('Grrr').thenReturn('Wuff') when(dog).bark('Miau').thenRaise(TypeError()) # With this configuration set up: assert dog.bark('Grrr') == 'Wuff' dog.bark('Miau') # will throw TypeError dog.bark('Wuff') # will throw unwanted interaction Stubbing can effectively be used as monkeypatching; usage shown with the `with` context managing:: with when(os.path).exists('/foo').thenReturn(True): ... Most of the time verifying your interactions is not necessary, because your code under tests implicitly verifies the return value by evaluating it. See :func:`verify` if you need to, see also :func:`expect` to setup expected call counts up front. If your function is pure side effect and does not return something, you can omit the specific answer. The default then is `None`:: when(manager).do_work() `when` verifies the method name, the expected argument signature, and the actual, factual arguments your code under test uses against the original object and its function so its easier to spot changing interfaces. Sometimes it's tedious to spell out all arguments:: from mockito import ANY, ARGS, KWARGS when(requests).get('http://example.com/', **KWARGS).thenReturn(...) when(os.path).exists(ANY) when(os.path).exists(ANY(str)) .. note:: You must :func:`unstub` after stubbing, or use `with` statement. Set ``strict=False`` to bypass the function signature checks. See related :func:`when2` which has a more pythonic interface. """ if isinstance(obj, str): obj = get_obj(obj) theMock = _get_mock(obj, strict=strict) class When(object): def __getattr__(self, method_name): return invocation.StubbedInvocation( theMock, method_name, strict=strict) return When() def when2(fn, *args, **kwargs): """Stub a function call with the given arguments Exposes a more pythonic interface than :func:`when`. See :func:`when` for more documentation. Returns `AnswerSelector` interface which exposes `thenReturn`, `thenRaise`, and `thenAnswer` as usual. Always `strict`. Usage:: # Given `dog` is an instance of a `Dog` when2(dog.bark, 'Miau').thenReturn('Wuff') .. note:: You must :func:`unstub` after stubbing, or use `with` statement. """ obj, name = get_obj_attr_tuple(fn) theMock = _get_mock(obj, strict=True) return invocation.StubbedInvocation(theMock, name)(*args, **kwargs) def patch(fn, attr_or_replacement, replacement=None): """Patch/Replace a function. This is really like monkeypatching, but *note* that all interactions will be recorded and can be verified. That is, using `patch` you stay in the domain of mockito. Two ways to call this. Either:: patch(os.path.exists, lambda str: True) # two arguments # OR patch(os.path, 'exists', lambda str: True) # three arguments If called with three arguments, the mode is *not* strict to allow *adding* methods. If called with two arguments, mode is always `strict`. .. note:: You must :func:`unstub` after stubbing, or use `with` statement. """ if replacement is None: replacement = attr_or_replacement return when2(fn, Ellipsis).thenAnswer(replacement) else: obj, name = fn, attr_or_replacement theMock = _get_mock(obj, strict=True) return invocation.StubbedInvocation( theMock, name, strict=False)(Ellipsis).thenAnswer(replacement) def expect(obj, strict=None, times=None, atleast=None, atmost=None, between=None): """Stub a function call, and set up an expected call count. Usage:: # Given `dog` is an instance of a `Dog` expect(dog, times=1).bark('Wuff').thenReturn('Miau') dog.bark('Wuff') dog.bark('Wuff') # will throw at call time: too many invocations # maybe if you need to ensure that `dog.bark()` was called at all verifyNoUnwantedInteractions() .. note:: You must :func:`unstub` after stubbing, or use `with` statement. See :func:`when`, :func:`when2`, :func:`verifyNoUnwantedInteractions` """ if strict is None: strict = True theMock = _get_mock(obj, strict=strict) verification_fn = _get_wanted_verification( times=times, atleast=atleast, atmost=atmost, between=between) class Expect(object): def __getattr__(self, method_name): return invocation.StubbedInvocation( theMock, method_name, verification=verification_fn, strict=strict) return Expect() def unstub(*objs): """Unstubs all stubbed methods and functions If you don't pass in any argument, *all* registered mocks and patched modules, classes etc. will be unstubbed. Note that additionally, the underlying registry will be cleaned. After an `unstub` you can't :func:`verify` anymore because all interactions will be forgotten. """ if objs: for obj in objs: mock_registry.unstub(obj) else: mock_registry.unstub_all() def forget_invocations(*objs): """Forget all invocations of given objs. If you already *call* mocks during your setup routine, you can now call ``forget_invocations`` at the end of your setup, and have a clean 'recording' for your actual test code. T.i. you don't have to count the invocations from your setup code anymore when using :func:`verify` afterwards. """ for obj in objs: theMock = _get_mock_or_raise(obj) theMock.clear_invocations() def verifyNoMoreInteractions(*objs): verifyNoUnwantedInteractions(*objs) for obj in objs: theMock = _get_mock_or_raise(obj) for i in theMock.invocations: if not i.verified: raise VerificationError("\nUnwanted interaction: %s" % i) def verifyZeroInteractions(*objs): """Verify that no methods have been called on given objs. Note that strict mocks usually throw early on unexpected, unstubbed invocations. Partial mocks ('monkeypatched' objects or modules) do not support this functionality at all, bc only for the stubbed invocations the actual usage gets recorded. So this function is of limited use, nowadays. """ for obj in objs: theMock = _get_mock_or_raise(obj) if len(theMock.invocations) > 0: raise VerificationError( "\nUnwanted interaction: %s" % theMock.invocations[0]) def verifyNoUnwantedInteractions(*objs): """Verifies that expectations set via `expect` are met E.g.:: expect(os.path, times=1).exists(...).thenReturn(True) os.path('/foo') verifyNoUnwantedInteractions(os.path) # ok, called once If you leave out the argument *all* registered objects will be checked. .. note:: **DANGERZONE**: If you did not :func:`unstub` correctly, it is possible that old registered mocks, from other tests leak. See related :func:`expect` """ if objs: theMocks = map(_get_mock_or_raise, objs) else: theMocks = mock_registry.get_registered_mocks() for mock in theMocks: for i in mock.stubbed_invocations: i.verify() def verifyStubbedInvocationsAreUsed(*objs): """Ensure stubs are actually used. This functions just ensures that stubbed methods are actually used. Its purpose is to detect interface changes after refactorings. It is meant to be invoked usually without arguments just before :func:`unstub`. """ if objs: theMocks = map(_get_mock_or_raise, objs) else: theMocks = mock_registry.get_registered_mocks() for mock in theMocks: for i in mock.stubbed_invocations: if not i.allow_zero_invocations and i.used < len(i.answers): raise VerificationError("\nUnused stub: %s" % i) mockito-python-1.2.2/mockito/signature.py000066400000000000000000000106511372607637100205370ustar00rootroot00000000000000 from . import matchers from .utils import contains_strict import functools import inspect import sys import types try: from inspect import signature, Parameter except ImportError: from funcsigs import signature, Parameter PY3 = sys.version_info >= (3,) def get_signature(obj, method_name): method = getattr(obj, method_name) # Eat self for unbound methods bc signature doesn't do it if PY3: if ( inspect.isclass(obj) and not inspect.ismethod(method) and not isinstance(obj.__dict__.get(method_name), staticmethod) ): method = functools.partial(method, None) else: if ( isinstance(method, types.UnboundMethodType) and method.__self__ is None ): method = functools.partial(method, None) try: return signature(method) except Exception: return None def match_signature(sig, args, kwargs): sig.bind(*args, **kwargs) return sig def match_signature_allowing_placeholders(sig, args, kwargs): # noqa: C901 # Let's face it. If this doesn't work out, we have to do it the hard # way and reimplement something like `sig.bind` with our specific # need for `...`, `*args`, and `**kwargs` support. if contains_strict(args, Ellipsis): # Invariant: Ellipsis as the sole argument should just pass, regardless # if it actually can consume an arg or the function does not take any # arguments at all if len(args) == 1: return has_kwargs = has_var_keyword(sig) # Ellipsis is always the last arg in args; it matches all keyword # arguments as well. So the strategy here is to strip off all # the keyword arguments from the signature, and do a partial # bind with the rest. params = [p for n, p in sig.parameters.items() if p.kind not in (Parameter.KEYWORD_ONLY, Parameter.VAR_KEYWORD)] sig = sig.replace(parameters=params) # Ellipsis should fill at least one argument. We strip it off if # it can stand for a `kwargs` argument. sig.bind_partial(*(args[:-1] if has_kwargs else args)) else: # `*args` should at least match one arg (t.i. not `*[]`), so we # keep it here. The value and its type is irrelevant in python. args_provided = contains_strict(args, matchers.ARGS_SENTINEL) # If we find the `**kwargs` sentinel we must remove it, bc its # name cannot be matched against the sig. kwargs_provided = matchers.KWARGS_SENTINEL in kwargs if kwargs_provided: kwargs = kwargs.copy() kwargs.pop(matchers.KWARGS_SENTINEL) if args_provided or kwargs_provided: try: sig.bind(*args, **kwargs) except TypeError as e: error = str(e) if 'too many positional arguments' in error: raise TypeError('no argument for *args left') if 'multiple values for argument' in error: raise if 'too many keyword arguments' in error: # PY<3.5 raise if 'got an unexpected keyword argument' in error: # PY>3.5 raise else: if kwargs_provided and not has_var_keyword(sig): pos_args = positional_arguments(sig) len_args = len(args) - int(args_provided) len_kwargs = len(kwargs) provided_args = len_args + len_kwargs # Substitute at least one argument for the `**kwargs`, # the user provided; t.i. do not allow kwargs to # satisfy an empty `{}`. if provided_args + 1 > pos_args: raise TypeError( 'no keyword argument for **kwargs left') else: # Without Ellipsis and the other stuff this would really be # straight forward. sig.bind(*args, **kwargs) return sig def positional_arguments(sig): return len([p for n, p in sig.parameters.items() if p.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD)]) def has_var_keyword(sig): return any(p for n, p in sig.parameters.items() if p.kind is Parameter.VAR_KEYWORD) mockito-python-1.2.2/mockito/spying.py000066400000000000000000000062211372607637100200450ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. '''Spying on real objects.''' import inspect from .mockito import when2 from .invocation import RememberedProxyInvocation from .mocking import Mock, _Dummy, mock_registry from .utils import get_obj __all__ = ['spy'] def spy(object): """Spy an object. Spying means that all functions will behave as before, so they will be side effects, but the interactions can be verified afterwards. Returns Dummy-like, almost empty object as proxy to `object`. The *returned* object must be injected and used by the code under test; after that all interactions can be verified as usual. T.i. the original object **will not be patched**, and has no further knowledge as before. E.g.:: import time time = spy(time) # inject time do_work(..., time) verify(time).time() """ if inspect.isclass(object) or inspect.ismodule(object): class_ = None else: class_ = object.__class__ class Spy(_Dummy): if class_: __class__ = class_ def __getattr__(self, method_name): return RememberedProxyInvocation(theMock, method_name) def __repr__(self): name = 'Spied' if class_: name += class_.__name__ return "<%s id=%s>" % (name, id(self)) obj = Spy() theMock = Mock(obj, strict=True, spec=object) mock_registry.register(obj, theMock) return obj def spy2(fn): # type: (...) -> None """Spy usage of given `fn`. Patches the module, class or object `fn` lives in, so that all interactions can be recorded; otherwise executes `fn` as before, so that all side effects happen as before. E.g.:: import time spy2(time.time) do_work(...) # nothing injected, uses global patched `time` module verify(time).time() Note that builtins often cannot be patched because they're read-only. """ if isinstance(fn, str): answer = get_obj(fn) else: answer = fn when2(fn, Ellipsis).thenAnswer(answer) mockito-python-1.2.2/mockito/utils.py000066400000000000000000000123131372607637100176730ustar00rootroot00000000000000 import importlib import inspect import sys import types import re PY3 = sys.version_info >= (3,) def contains_strict(seq, element): return any(item is element for item in seq) def newmethod(fn, obj): return types.MethodType(fn, obj) def get_function_host(fn): """Destructure a given function into its host and its name. The 'host' of a function is a module, for methods it is usually its instance or its class. This is safe only for methods, for module wide, globally declared names it must be considered experimental. For all reasonable fn: ``getattr(*get_function_host(fn)) == fn`` Returns tuple (host, fn-name) Otherwise should raise TypeError """ obj = None try: name = fn.__name__ obj = fn.__self__ except AttributeError: pass if obj is None: # Due to how python imports work, everything that is global on a module # level must be regarded as not safe here. For now, we go for the extra # mile, TBC, because just specifying `os.path.exists` would be 'cool'. # # TLDR;: # E.g. `inspect.getmodule(os.path.exists)` returns `genericpath` bc # that's where `exists` is defined and comes from. But from the point # of view of the user `exists` always comes and is used from `os.path` # which points e.g. to `ntpath`. We thus must patch `ntpath`. # But that's the same for most imports:: # # # b.py # from a import foo # # Now asking `getmodule(b.foo)` it tells you `a`, but we access and use # `b.foo` and we therefore must patch `b`. obj, name = find_invoking_frame_and_try_parse() # safety check! assert getattr(obj, name) == fn return obj, name FIND_ID = re.compile(r'.*\s*.*(?:when2|patch|spy2)\(\s*(.+?)[,\)]', re.M) def find_invoking_frame_and_try_parse(): # Actually we just want the first frame in user land; we're open for # refactorings here and don't yet decide on which frame exactly we hit # that user land. stack = inspect.stack(3)[2:10] for frame_info in stack: # Within `patch` and `spy2` we delegate to `when2` but that's not # user land code if frame_info[3] in ('patch', 'spy2'): continue source = ''.join(frame_info[4]) m = FIND_ID.match(source) if m: # id should be something like `os.path.exists` etc. id = m.group(1) parts = id.split('.') if len(parts) < 2: raise TypeError("can't guess origin of '%s'" % id) frame = frame_info[0] vars = frame.f_globals.copy() vars.update(frame.f_locals) # Now that's a simple reduce; we get the initial value from the # locally available `vars`, and then reduce the middle parts via # `getattr`. The last path component gets not resolved, but is # returned as plain string value. obj = vars.get(parts[0]) for part in parts[1:-1]: obj = getattr(obj, part) return obj, parts[-1] raise TypeError('could not destructure first argument') def get_obj(path): """Return obj for given dotted path. Typical inputs for `path` are 'os' or 'os.path' in which case you get a module; or 'os.path.exists' in which case you get a function from that module. Just returns the given input in case it is not a str. Note: Relative imports not supported. Raises ImportError or AttributeError as appropriate. """ # Since we usually pass in mocks here; duck typing is not appropriate # (mocks respond to every attribute). if not isinstance(path, str): return path if path.startswith('.'): raise TypeError('relative imports are not supported') parts = path.split('.') head, tail = parts[0], parts[1:] obj = importlib.import_module(head) # Normally a simple reduce, but we go the extra mile # for good exception messages. for i, name in enumerate(tail): try: obj = getattr(obj, name) except AttributeError: # Note the [:i] instead of [:i+1], so we get the path just # *before* the AttributeError, t.i. the part of it that went ok. module = '.'.join([head] + tail[:i]) try: importlib.import_module(module) except ImportError: raise AttributeError( "object '%s' has no attribute '%s'" % (module, name)) else: raise AttributeError( "module '%s' has no attribute '%s'" % (module, name)) return obj def get_obj_attr_tuple(path): """Split path into (obj, attribute) tuple. Given `path` is 'os.path.exists' will thus return `(os.path, 'exists')` If path is not a str, delegates to `get_function_host(path)` """ if not isinstance(path, str): return get_function_host(path) if path.startswith('.'): raise TypeError('relative imports are not supported') try: leading, end = path.rsplit('.', 1) except ValueError: raise TypeError('path must have dots') return get_obj(leading), end mockito-python-1.2.2/mockito/verification.py000066400000000000000000000124141372607637100212170ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import operator __all__ = ['never', 'VerificationError'] class VerificationError(AssertionError): '''Indicates error during verification of invocations. Raised if verification fails. Error message contains the cause. ''' pass __tracebackhide__ = operator.methodcaller("errisinstance", VerificationError) class AtLeast(object): def __init__(self, wanted_count): self.wanted_count = wanted_count def verify(self, invocation, actual_count): if actual_count < self.wanted_count: raise VerificationError("\nWanted at least: %i, actual times: %i" % (self.wanted_count, actual_count)) def __repr__(self): return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count) class AtMost(object): def __init__(self, wanted_count): self.wanted_count = wanted_count def verify(self, invocation, actual_count): if actual_count > self.wanted_count: raise VerificationError("\nWanted at most: %i, actual times: %i" % (self.wanted_count, actual_count)) def __repr__(self): return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count) class Between(object): def __init__(self, wanted_from, wanted_to): self.wanted_from = wanted_from self.wanted_to = wanted_to def verify(self, invocation, actual_count): if actual_count < self.wanted_from or actual_count > self.wanted_to: raise VerificationError( "\nWanted between: [%i, %i], actual times: %i" % (self.wanted_from, self.wanted_to, actual_count)) def __repr__(self): return "<%s [%s, %s]>" % ( type(self).__name__, self.wanted_from, self.wanted_to) class Times(object): def __init__(self, wanted_count): self.wanted_count = wanted_count def verify(self, invocation, actual_count): if actual_count == self.wanted_count: return if actual_count == 0: invocations = ( [ invoc for invoc in invocation.mock.invocations if invoc.method_name == invocation.method_name ] or invocation.mock.invocations or ['Nothing'] ) raise VerificationError( """ Wanted but not invoked: %s Instead got: %s """ % ( invocation, "\n ".join( str(invoc) for invoc in reversed(invocations) ) ) ) else: if self.wanted_count == 0: raise VerificationError( "\nUnwanted invocation of %s, times: %i" % (invocation, actual_count)) else: raise VerificationError("\nWanted times: %i, actual times: %i" % (self.wanted_count, actual_count)) def __repr__(self): return "<%s wanted=%s>" % (type(self).__name__, self.wanted_count) class InOrder(object): '''Verifies invocations in order. Verifies if invocation was in expected order, and if yes -- degrades to original Verifier (AtLeast, Times, Between, ...). ''' def __init__(self, original_verification): ''' @param original_verification: Original verifiaction to degrade to if order of invocation was ok. ''' self.original_verification = original_verification def verify(self, wanted_invocation, count): for invocation in reversed(wanted_invocation.mock.invocations): if not invocation.verified_inorder: if not wanted_invocation.matches(invocation): raise VerificationError( '\nWanted %s to be invoked,' '\ngot %s instead.' % (wanted_invocation, invocation)) invocation.verified_inorder = True break # proceed with original verification self.original_verification.verify(wanted_invocation, count) never = 0 mockito-python-1.2.2/setup.py000077500000000000000000000024421372607637100162330ustar00rootroot00000000000000from setuptools import setup import sys import re import ast _version_re = re.compile(r'__version__\s+=\s+(.*)') with open('mockito/__init__.py', 'rb') as f: version = str(ast.literal_eval(_version_re.search( f.read().decode('utf-8')).group(1))) install_requires = ['funcsigs'] if sys.version_info < (3,) else [] setup(name='mockito', version=version, packages=['mockito'], url='https://github.com/kaste/mockito-python', maintainer='herr.kaste', maintainer_email='herr.kaste@gmail.com', license='MIT', description='Spying framework', long_description=open('README.rst').read(), install_requires=install_requires, classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Topic :: Software Development :: Testing', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', ]) mockito-python-1.2.2/tests/000077500000000000000000000000001372607637100156565ustar00rootroot00000000000000mockito-python-1.2.2/tests/__init__.py000066400000000000000000000000001372607637100177550ustar00rootroot00000000000000mockito-python-1.2.2/tests/classmethods_test.py000066400000000000000000000163401372607637100217640ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from mockito import unstub, verify, when from mockito.verification import VerificationError from .test_base import TestBase class Dog: @classmethod def bark(cls): return "woof!" class Cat: @classmethod def meow(cls, m): return cls.__name__ + " " + str(m) class Lion(object): @classmethod def roar(cls): return "Rrrrr!" class ClassMethodsTest(TestBase): def tearDown(self): unstub() def testUnstubs(self): when(Dog).bark().thenReturn("miau!") unstub() self.assertEqual("woof!", Dog.bark()) # TODO decent test case please :) without testing irrelevant implementation # details def testUnstubShouldPreserveMethodType(self): when(Dog).bark().thenReturn("miau!") unstub() self.assertTrue(isinstance(Dog.__dict__.get("bark"), classmethod)) def testStubs(self): self.assertEqual("woof!", Dog.bark()) when(Dog).bark().thenReturn("miau!") self.assertEqual("miau!", Dog.bark()) def testStubsClassesDerivedFromTheObjectClass(self): self.assertEqual("Rrrrr!", Lion.roar()) when(Lion).roar().thenReturn("miau!") self.assertEqual("miau!", Lion.roar()) def testVerifiesMultipleCallsOnClassmethod(self): when(Dog).bark().thenReturn("miau!") Dog.bark() Dog.bark() verify(Dog, times=2).bark() def testFailsVerificationOfMultipleCallsOnClassmethod(self): when(Dog).bark().thenReturn("miau!") Dog.bark() self.assertRaises(VerificationError, verify(Dog, times=2).bark) def testStubsAndVerifiesClassmethod(self): when(Dog).bark().thenReturn("miau!") self.assertEqual("miau!", Dog.bark()) verify(Dog).bark() def testPreservesClassArgumentAfterUnstub(self): self.assertEqual("Cat foo", Cat.meow("foo")) when(Cat).meow("foo").thenReturn("bar") self.assertEqual("bar", Cat.meow("foo")) unstub() self.assertEqual("Cat foo", Cat.meow("foo")) class Retriever: @classmethod def retrieve(cls, item): return item class TrickDog(Dog, Retriever): pass class InheritedClassMethodsTest(TestBase): def tearDown(self): unstub() def testUnstubs(self): when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("ball") unstub() self.assertEqual("woof!", TrickDog.bark()) self.assertEqual("stick", TrickDog.retrieve("stick")) def testStubs(self): self.assertEqual("woof!", TrickDog.bark()) self.assertEqual("stick", TrickDog.retrieve("stick")) when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("ball") self.assertEqual("miau!", TrickDog.bark()) self.assertEqual("ball", TrickDog.retrieve("stick")) def testVerifiesMultipleCallsOnClassmethod(self): when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("ball") TrickDog.bark() TrickDog.bark() TrickDog.retrieve("stick") TrickDog.retrieve("stick") verify(TrickDog, times=2).bark() verify(TrickDog, times=2).retrieve("stick") def testFailsVerificationOfMultipleCallsOnClassmethod(self): when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("bark") TrickDog.bark() TrickDog.retrieve("stick") self.assertRaises(VerificationError, verify(TrickDog, times=2).bark) self.assertRaises(VerificationError, verify(TrickDog, times=2).retrieve) def testStubsAndVerifiesClassmethod(self): when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("ball") self.assertEqual("miau!", TrickDog.bark()) self.assertEqual("ball", TrickDog.retrieve("stick")) verify(TrickDog).bark() verify(TrickDog).retrieve("stick") def testPreservesSuperClassClassMethodWhenStubbed(self): self.assertEqual("woof!", Dog.bark()) self.assertEqual("stick", Retriever.retrieve("stick")) self.assertEqual("woof!", TrickDog.bark()) self.assertEqual("stick", TrickDog.retrieve("stick")) when(TrickDog).bark().thenReturn("miau!") when(TrickDog).retrieve("stick").thenReturn("ball") self.assertEqual("miau!", TrickDog.bark()) self.assertEqual("ball", TrickDog.retrieve("stick")) self.assertEqual("woof!", Dog.bark()) self.assertEqual("stick", Retriever.retrieve("stick")) def testDoubleStubStubWorksAfterUnstub(self): when(TrickDog).retrieve("stick").thenReturn("ball") when(TrickDog).retrieve("stick").thenReturn("cat") unstub() self.assertEqual("stick", TrickDog.retrieve("stick")) def testUnStubWorksOnClassAndSuperClass(self): self.assertEqual("stick", Retriever.retrieve("stick")) self.assertEqual("stick", TrickDog.retrieve("stick")) when(Retriever).retrieve("stick").thenReturn("ball") self.assertEqual("ball", Retriever.retrieve("stick")) self.assertEqual("ball", TrickDog.retrieve("stick")) when(TrickDog).retrieve("stick").thenReturn("cat") self.assertEqual("ball", Retriever.retrieve("stick")) self.assertEqual("cat", TrickDog.retrieve("stick")) unstub(TrickDog) self.assertEqual("ball", Retriever.retrieve("stick")) self.assertEqual("ball", TrickDog.retrieve("stick")) unstub(Retriever) self.assertEqual("stick", Retriever.retrieve("stick")) self.assertEqual("stick", TrickDog.retrieve("stick")) def testReverseOrderWhenUnstubbing(self): when(Retriever).retrieve("stick").thenReturn("ball") when(TrickDog).retrieve("stick").thenReturn("cat") unstub(Retriever) self.assertEqual("stick", Retriever.retrieve("stick")) self.assertEqual("cat", TrickDog.retrieve("stick")) unstub(TrickDog) self.assertEqual("stick", Retriever.retrieve("stick")) self.assertEqual("stick", TrickDog.retrieve("stick")) mockito-python-1.2.2/tests/conftest.py000066400000000000000000000001451372607637100200550ustar00rootroot00000000000000 import pytest @pytest.fixture def unstub(): from mockito import unstub yield unstub() mockito-python-1.2.2/tests/ellipsis_test.py000066400000000000000000000266211372607637100211220ustar00rootroot00000000000000 import pytest from collections import namedtuple from mockito import when, args, kwargs, invocation, mock class Dog(object): def bark(self, sound): return "%s!" % sound def waggle(self): return 'waggle' class CallSignature(namedtuple('CallSignature', 'args kwargs')): def raises(self, reason): return pytest.mark.xfail(self, raises=reason, strict=True) def sig(*args, **kwargs): return CallSignature(args, kwargs) class TestCallMethodWithSignature: def testNoArg(self): rex = Dog() when(rex).waggle().thenReturn('wuff') assert rex.waggle() == 'wuff' with pytest.raises(TypeError): rex.waggle(1) with pytest.raises(TypeError): rex.waggle(Ellipsis) with pytest.raises(TypeError): rex.waggle(args) with pytest.raises(TypeError): rex.waggle(kwargs) with pytest.raises(TypeError): rex.waggle(*args) with pytest.raises(TypeError): rex.waggle(**kwargs) def testExpectingSpecificInputAsPositionalArgument(self): rex = Dog() when(rex).bark(1).thenReturn('wuff') assert rex.bark(1) == 'wuff' with pytest.raises(invocation.InvocationError): rex.bark(sound=1) with pytest.raises(invocation.InvocationError): rex.bark(Ellipsis) with pytest.raises(invocation.InvocationError): rex.bark(args) with pytest.raises(invocation.InvocationError): rex.bark(*args) with pytest.raises(invocation.InvocationError): rex.bark(kwargs) with pytest.raises(TypeError): rex.bark(1, 2) with pytest.raises(TypeError): rex.bark(wuff=1) with pytest.raises(TypeError): rex.bark(**kwargs) def testExpectingSpecificInputAsKeyword(self): rex = Dog() when(rex).bark(sound=1).thenReturn('wuff') assert rex.bark(sound=1) == 'wuff' with pytest.raises(invocation.InvocationError): rex.bark(1) with pytest.raises(invocation.InvocationError): rex.bark(Ellipsis) with pytest.raises(invocation.InvocationError): rex.bark(args) with pytest.raises(invocation.InvocationError): rex.bark(*args) with pytest.raises(invocation.InvocationError): rex.bark(kwargs) with pytest.raises(TypeError): rex.bark(1, 2) with pytest.raises(TypeError): rex.bark(wuff=1) with pytest.raises(TypeError): rex.bark(**kwargs) def testExpectingStarKwargs(self): rex = Dog() when(rex).bark(**kwargs).thenReturn('wuff') assert rex.bark(sound='miau') == 'wuff' with pytest.raises(invocation.InvocationError): rex.bark('miau') with pytest.raises(invocation.InvocationError): rex.bark(Ellipsis) with pytest.raises(invocation.InvocationError): rex.bark(kwargs) with pytest.raises(invocation.InvocationError): rex.bark(args) with pytest.raises(TypeError): rex.bark(wuff='miau') with pytest.raises(TypeError): rex.bark(**kwargs) def testExpectingEllipsis(self): rex = Dog() when(rex).bark(Ellipsis).thenReturn('wuff') assert rex.bark('miau') == 'wuff' with pytest.raises(TypeError): rex.bark('miau', 'miau') assert rex.bark(sound='miau') == 'wuff' with pytest.raises(TypeError): rex.bark(wuff='miau') assert rex.bark(Ellipsis) == 'wuff' assert rex.bark(args) == 'wuff' assert rex.bark(*args) == 'wuff' assert rex.bark(kwargs) == 'wuff' with pytest.raises(TypeError): rex.bark(**kwargs) == 'wuff' def testExpectingStarArgs(self): rex = Dog() when(rex).bark(*args).thenReturn('wuff') assert rex.bark('miau') == 'wuff' with pytest.raises(invocation.InvocationError): rex.bark(sound='miau') with pytest.raises(TypeError): rex.bark(wuff='miau') assert rex.bark(*args) == 'wuff' assert rex.bark(Ellipsis) == 'wuff' with pytest.raises(TypeError): rex.bark(**kwargs) class TestEllipsises: # In python3 `bark(...)` is actually valid, but the tests must # be downwards compatible to python 2 @pytest.mark.parametrize('call', [ sig(), sig('Wuff'), sig('Wuff', 'Wuff'), sig('Wuff', then='Wuff'), sig(then='Wuff'), ]) def testEllipsisAsSoleArgumentAlwaysPasses(self, call): rex = mock() when(rex).bark(Ellipsis).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff'), sig('Wuff', 'Wuff'), sig('Wuff', then='Wuff'), ]) def testEllipsisAsSecondArgumentPasses(self, call): rex = mock() when(rex).bark('Wuff', Ellipsis).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig(then='Wuff'), ]) def testEllipsisAsSecondArgumentRejections(self, call): rex = mock() when(rex).bark('Wuff', Ellipsis).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig('Wuff'), sig('Wuff', 'Wuff'), ]) def testArgsAsSoleArgumentPasses(self, call): rex = mock() when(rex).bark(*args).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff', then='Wuff'), sig(then='Wuff'), ]) def testArgsAsSoleArgumentRejections(self, call): rex = mock() when(rex).bark(*args).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff'), sig('Wuff', 'Wuff'), ]) def testArgsAsSecondArgumentPasses(self, call): rex = mock() when(rex).bark('Wuff', *args).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig('Wuff', then='Wuff'), sig(then='Wuff'), ]) def testArgsAsSecondArgumentRejections(self, call): rex = mock() when(rex).bark('Wuff', *args).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff', then='Wuff'), sig('Wuff', 'Wuff', then='Wuff'), ]) def testArgsBeforeConcreteKwargPasses(self, call): rex = mock() when(rex).bark('Wuff', *args, then='Wuff').thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig('Wuff'), sig('Wuff', 'Wuff'), sig(then='Wuff'), ]) def testArgsBeforeConcreteKwargRejections(self, call): rex = mock() when(rex).bark('Wuff', *args, then='Wuff').thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig(then='Wuff'), sig(then='Wuff', later='Waff') ]) def testKwargsAsSoleArgumentPasses(self, call): rex = mock() when(rex).bark(**kwargs).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff'), sig('Wuff', 'Wuff'), sig('Wuff', then='Wuff'), sig('Wuff', 'Wuff', then='Wuff'), ]) def testKwargsAsSoleArgumentRejections(self, call): rex = mock() when(rex).bark(**kwargs).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(then='Wuff'), sig(then='Wuff', later='Waff'), sig(later='Waff', then='Wuff'), ]) def testKwargsAsSecondKwargPasses(self, call): rex = mock() when(rex).bark(then='Wuff', **kwargs).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig('Wuff'), sig('Wuff', 'Wuff'), sig('Wuff', then='Wuff'), sig('Wuff', 'Wuff', then='Wuff'), sig(first='Wuff', later='Waff') ]) def testKwargsAsSecondKwargRejections(self, call): rex = mock() when(rex).bark(then='Wuff', **kwargs).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig('Wuff', then='Waff'), sig('Wuff', 'Wuff', then='Waff'), sig('Wuff', then='Waff', later='Woff'), sig('Wuff', first="Wiff", then='Waff', later='Woff'), sig('Wuff', 'Wuff', then='Waff', later="Woff"), ]) def testCombinedArgsAndKwargsPasses(self, call): rex = mock() when(rex).bark('Wuff', *args, then='Waff', **kwargs).thenReturn('Miau') assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(), sig('Wuff'), sig('Wuff', 'Wuff'), sig(later='Woff'), sig('Wuff', later='Woff'), ]) def testCombinedArgsAndKwargsRejections(self, call): rex = mock() when(rex).bark('Wuff', *args, then='Waff', **kwargs).thenReturn('Miau') with pytest.raises(AssertionError): assert rex.bark(*call.args, **call.kwargs) == 'Miau' @pytest.mark.parametrize('call', [ sig(Ellipsis), ]) def testEllipsisMustBeLastThing(self, call): rex = mock() when(rex).bark(*call.args, **call.kwargs).thenReturn('Miau') @pytest.mark.parametrize('call', [ sig(Ellipsis, 'Wuff'), sig(Ellipsis, then='Wuff'), sig(Ellipsis, 'Wuff', then='Waff'), ]) def testEllipsisMustBeLastThingRejections(self, call): rex = mock() with pytest.raises(TypeError): when(rex).bark(*call.args, **call.kwargs).thenReturn('Miau') def testArgsMustUsedAsStarArg(self): rex = mock() with pytest.raises(TypeError): when(rex).bark(args).thenReturn('Miau') def testKwargsMustBeUsedAsStarKwarg(self): rex = mock() with pytest.raises(TypeError): when(rex).bark(kwargs).thenReturn('Miau') with pytest.raises(TypeError): when(rex).bark(*kwargs).thenReturn('Miau') def testNiceFormattingForEllipsis(self): m = mock() m.strict = False inv = invocation.StubbedInvocation(m, 'bark', None) inv(Ellipsis) assert repr(inv) == 'bark(...)' def testNiceFormattingForArgs(self): m = mock() m.strict = False inv = invocation.StubbedInvocation(m, 'bark', None) inv(*args) assert repr(inv) == 'bark(*args)' def testNiceFormattingForKwargs(self): m = mock() m.strict = False inv = invocation.StubbedInvocation(m, 'bark', None) inv(**kwargs) assert repr(inv) == 'bark(**kwargs)' mockito-python-1.2.2/tests/instancemethods_test.py000066400000000000000000000335441372607637100224700ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from .test_base import TestBase from mockito import ( mock, when, expect, unstub, ANY, verify, verifyNoMoreInteractions, verifyZeroInteractions, verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed) from mockito.invocation import InvocationError from mockito.verification import VerificationError pytestmark = pytest.mark.usefixtures("unstub") class Dog(object): def waggle(self): return "Wuff!" def bark(self, sound): return "%s!" % sound def do_default_bark(self): return self.bark('Wau') def __call__(self): pass class InstanceMethodsTest(TestBase): def tearDown(self): unstub() def testUnstubClassMethod(self): original_method = Dog.waggle when(Dog).waggle().thenReturn('Nope!') unstub() rex = Dog() self.assertEqual('Wuff!', rex.waggle()) self.assertEqual(original_method, Dog.waggle) def testUnstubMockedInstanceMethod(self): rex = Dog() when(rex).waggle().thenReturn('Nope!') assert rex.waggle() == 'Nope!' unstub() assert rex.waggle() == 'Wuff!' def testUnstubMockedInstanceDoesNotHideTheClass(self): when(Dog).waggle().thenReturn('Nope!') rex = Dog() when(rex).waggle().thenReturn('Sure!') assert rex.waggle() == 'Sure!' unstub() assert rex.waggle() == 'Wuff!' def testStubAnInstanceMethod(self): when(Dog).waggle().thenReturn('Boing!') rex = Dog() self.assertEqual('Boing!', rex.waggle()) def testStubsAnInstanceMethodWithAnArgument(self): when(Dog).bark('Miau').thenReturn('Wuff') rex = Dog() self.assertEqual('Wuff', rex.bark('Miau')) def testInvokeAStubbedMethodFromAnotherMethod(self): when(Dog).bark('Wau').thenReturn('Wuff') rex = Dog() self.assertEqual('Wuff', rex.do_default_bark()) verify(Dog).bark('Wau') def testYouCantStubAnUnknownMethodInStrictMode(self): try: when(Dog).barks('Wau').thenReturn('Wuff') self.fail( 'Stubbing an unknown method should have thrown a exception') except InvocationError: pass def testStubUnknownMethodInLooseMode(self): when(Dog, strict=False).walk() rex = Dog() rex.walk() unstub() with pytest.raises(AttributeError): rex.walk with pytest.raises(AttributeError): Dog.walk def testAddNewMethodOnInstanceInLooseMode(self): rex = Dog() when(rex, strict=False).walk() rex.walk() unstub() with pytest.raises(AttributeError): rex.walk def testThrowEarlyIfCallingWithUnexpectedArgumentsInStrictMode(self): rex = Dog() when(rex).bark('Miau').thenReturn('Wuff') with pytest.raises(InvocationError): rex.bark('Shhh') def testNiceErrorMessageOnUnexpectedCall(self): theMock = mock(strict=True) when(theMock).foo('bar') when(theMock).foo(12, baz='boz') when(theMock).bar('foo') # <==== omitted from output! with pytest.raises(InvocationError) as exc: theMock.foo(True, None) assert str(exc.value) == ''' Called but not expected: foo(True, None) Stubbed invocations are: foo('bar') foo(12, baz='boz') ''' def testStubCallableObject(self): when(Dog).__call__().thenReturn('done') rex = Dog() # <= important. not stubbed assert rex() == 'done' def testReturnNoneIfCallingWithUnexpectedArgumentsIfNotStrict(self): when(Dog, strict=False).bark('Miau').thenReturn('Wuff') rex = Dog() self.assertEqual(None, rex.bark('Shhh')) def testStubInstancesInsteadOfClasses(self): rex = Dog() when(rex).bark('Miau').thenReturn('Wuff') self.assertEqual('Wuff', rex.bark('Miau')) verify(rex, times=1).bark(ANY) max = Dog() self.assertEqual('Miau!', max.bark('Miau')) def testUnstubInstance(self): rex = Dog() when(rex).bark('Miau').thenReturn('Wuff') unstub() assert rex.bark('Miau') == 'Miau!' def testNoExplicitReturnValueMeansNone(self): when(Dog).bark('Miau').thenReturn() rex = Dog() self.assertEqual(None, rex.bark('Miau')) def testForgottenThenReturnMeansReturnNone(self): when(Dog).bark('Miau') when(Dog).waggle() rex = Dog() self.assertEqual(None, rex.bark('Miau')) self.assertEqual(None, rex.waggle()) class TestVerifyInteractions: class TestZeroInteractions: def testVerifyNoMoreInteractionsWorks(self): when(Dog).bark('Miau') verifyNoMoreInteractions(Dog) def testVerifyZeroInteractionsWorks(self): when(Dog).bark('Miau') verifyZeroInteractions(Dog) class TestOneInteraction: def testNothingVerifiedVerifyNoMoreInteractionsRaises(self): when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') with pytest.raises(VerificationError): verifyNoMoreInteractions(Dog) def testIfVerifiedVerifyNoMoreInteractionsPasses(self): when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') verify(Dog).bark('Miau') verifyNoMoreInteractions(Dog) def testNothingVerifiedVerifyZeroInteractionsRaises(self): when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') with pytest.raises(VerificationError): verifyZeroInteractions(Dog) def testIfVerifiedVerifyZeroInteractionsStillRaises(self): when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') verify(Dog).bark('Miau') with pytest.raises(VerificationError): verifyZeroInteractions(Dog) class TestEnsureStubsAreUsed: def testBarkOnUnusedStub(self): when(Dog).bark('Miau') with pytest.raises(VerificationError): verifyStubbedInvocationsAreUsed(Dog) class TestPassIfExplicitlyVerified: @pytest.mark.parametrize('verification', [ {'times': 0}, {'between': [0, 3]} ]) def testPassIfExplicitlyVerified(self, verification): dog = mock() when(dog).waggle().thenReturn('Sure') verify(dog, **verification).waggle() verifyStubbedInvocationsAreUsed(dog) def testWildcardCallSignatureOnVerify(self): dog = mock() when(dog).waggle(1).thenReturn('Sure') verify(dog, times=0).waggle(Ellipsis) verifyStubbedInvocationsAreUsed(dog) @pytest.mark.xfail(reason='Not implemented.') def testPassIfVerifiedZeroInteractions(self): dog = mock() when(dog).waggle(1).thenReturn('Sure') verifyZeroInteractions(dog) verifyStubbedInvocationsAreUsed(dog) @pytest.mark.xfail(reason='Not implemented.') def testPassIfVerifiedNoMoreInteractions(self): dog = mock() when(dog).waggle(1).thenReturn('Sure') verifyNoMoreInteractions(dog) verifyStubbedInvocationsAreUsed(dog) def testWildacardCallSignatureOnStub(self): dog = mock() when(dog).waggle(Ellipsis).thenReturn('Sure') verify(dog, times=0).waggle(1) verifyStubbedInvocationsAreUsed(dog) def testPassIfExplicitlyVerified4(self): dog = mock() when(dog).waggle(1).thenReturn('Sure') when(dog).waggle(2).thenReturn('Sure') verify(dog, times=0).waggle(Ellipsis) verifyStubbedInvocationsAreUsed(dog) class TestPassIfImplicitlyVerifiedViaExpect: @pytest.mark.parametrize('verification', [ {'times': 0}, {'between': [0, 3]} ]) def testPassIfImplicitlyVerified(self, verification): dog = mock() expect(dog, **verification).waggle().thenReturn('Sure') verifyStubbedInvocationsAreUsed(dog) def testPassUsedOnceImplicitAnswer(self): when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') verifyStubbedInvocationsAreUsed(Dog) def testPassUsedOnce(self): dog = mock() when(dog).waggle().thenReturn('Sure') dog.waggle() verifyStubbedInvocationsAreUsed(dog) def testFailSecondStubNotUsed(self): when(Dog).bark('Miau') when(Dog).waggle() rex = Dog() rex.bark('Miau') with pytest.raises(VerificationError): verifyStubbedInvocationsAreUsed(Dog) def testFailSecondStubSameMethodUnused(self): when(Dog).bark('Miau') when(Dog).bark('Grrr') rex = Dog() rex.bark('Miau') with pytest.raises(VerificationError): verifyStubbedInvocationsAreUsed(Dog) def testPassTwoStubsOnSameMethodUsed(self): when(Dog).bark('Miau') when(Dog).bark('Grrr') rex = Dog() rex.bark('Miau') rex.bark('Grrr') verifyStubbedInvocationsAreUsed(Dog) def testPassOneCatchAllOneSpecificStubBothUsed(self): when(Dog).bark(Ellipsis) when(Dog).bark('Miau') rex = Dog() rex.bark('Miau') rex.bark('Grrr') verifyStubbedInvocationsAreUsed(Dog) def testFailSecondAnswerUnused(self): when(Dog).bark('Miau').thenReturn('Yep').thenReturn('Nop') rex = Dog() rex.bark('Miau') with pytest.raises(VerificationError): verifyStubbedInvocationsAreUsed(Dog) @pytest.mark.usefixtures('unstub') class TestImplicitVerificationsUsingExpect: @pytest.fixture(params=[ {'times': 2}, {'atmost': 2}, {'between': [1, 2]} ], ids=['times', 'atmost', 'between']) def verification(self, request): return request.param def testFailImmediatelyIfWantedCountExceeds(self, verification): rex = Dog() expect(rex, **verification).bark('Miau').thenReturn('Wuff') rex.bark('Miau') rex.bark('Miau') with pytest.raises(InvocationError): rex.bark('Miau') def testVerifyNoMoreInteractionsWorks(self, verification): rex = Dog() expect(rex, **verification).bark('Miau').thenReturn('Wuff') rex.bark('Miau') rex.bark('Miau') verifyNoMoreInteractions(rex) def testNoUnwantedInteractionsWorks(self, verification): rex = Dog() expect(rex, **verification).bark('Miau').thenReturn('Wuff') rex.bark('Miau') rex.bark('Miau') verifyNoUnwantedInteractions(rex) @pytest.mark.parametrize('verification', [ {'times': 2}, {'atleast': 2}, {'between': [1, 2]} ], ids=['times', 'atleast', 'between']) def testVerifyNoMoreInteractionsBarksIfUnsatisfied(self, verification): rex = Dog() expect(rex, **verification).bark('Miau').thenReturn('Wuff') with pytest.raises(VerificationError): verifyNoMoreInteractions(rex) @pytest.mark.parametrize('verification', [ {'times': 2}, {'atleast': 2}, {'between': [1, 2]} ], ids=['times', 'atleast', 'between']) def testNoUnwantedInteractionsBarksIfUnsatisfied(self, verification): rex = Dog() expect(rex, **verification).bark('Miau').thenReturn('Wuff') with pytest.raises(VerificationError): verifyNoUnwantedInteractions(rex) def testNoUnwantedInteractionsForAllRegisteredObjects(self): rex = Dog() mox = Dog() expect(rex, times=1).bark('Miau') expect(mox, times=1).bark('Miau') rex.bark('Miau') mox.bark('Miau') verifyNoUnwantedInteractions() def testUseWhenAndExpectTogetherVerifyNoUnwatedInteractions(self): rex = Dog() when(rex).waggle() expect(rex, times=1).bark('Miau') rex.waggle() rex.bark('Miau') verifyNoUnwantedInteractions() def testExpectWitoutVerification(self): rex = Dog() expect(rex).bark('Miau').thenReturn('Wuff') verifyNoMoreInteractions(rex) rex.bark('Miau') with pytest.raises(VerificationError): verifyNoMoreInteractions(rex) # Where to put this test? During first implementation I broke this def testEnsureWhenGetsNotConfused(self): m = mock() when(m).foo(1).thenReturn() m.foo(1) with pytest.raises(VerificationError): verifyNoMoreInteractions(m) def testEnsureMultipleExpectsArentConfused(self): rex = Dog() expect(rex, times=1).bark('Miau').thenReturn('Wuff') expect(rex, times=1).waggle().thenReturn('Wuff') rex.bark('Miau') rex.waggle() mockito-python-1.2.2/tests/late_imports_test.py000066400000000000000000000050301372607637100217670ustar00rootroot00000000000000 import pytest from mockito.utils import get_obj, get_obj_attr_tuple import sys PY3 = sys.version_info >= (3,) def foo(): pass class TestLateImports: def testOs(self): import os assert get_obj('os') is os def testOsPath(self): import os.path assert get_obj('os.path') is os.path def testOsPathExists(self): import os.path assert get_obj('os.path.exists') is os.path.exists def testOsPathWhatever(self): with pytest.raises(AttributeError) as exc: get_obj('os.path.whatever') assert str(exc.value) == "module 'os.path' has no attribute 'whatever'" def testOsPathExistsForever(self): with pytest.raises(AttributeError) as exc: get_obj('os.path.exists.forever') assert str(exc.value) == \ "object 'os.path.exists' has no attribute 'forever'" def testOsPathExistsForeverAndEver(self): with pytest.raises(AttributeError) as exc: get_obj('os.path.exists.forever.and.ever') assert str(exc.value) == \ "object 'os.path.exists' has no attribute 'forever'" def testUnknownMum(self): with pytest.raises(ImportError) as exc: assert get_obj('mum') is foo if PY3: assert str(exc.value) == "No module named 'mum'" else: assert str(exc.value) == "No module named mum" def testUnknownMumFoo(self): with pytest.raises(ImportError) as exc: assert get_obj('mum.foo') is foo if PY3: assert str(exc.value) == "No module named 'mum'" else: assert str(exc.value) == "No module named mum" def testReturnGivenObject(self): import os assert get_obj(os) == os assert get_obj(os.path) == os.path assert get_obj(2) == 2 def testDisallowRelativeImports(self): with pytest.raises(TypeError): get_obj('.mum') class TestReturnTuple: def testOs(self): with pytest.raises(TypeError): get_obj_attr_tuple('os') def testOsPath(self): import os assert get_obj_attr_tuple('os.path') == (os, 'path') def testOsPathExists(self): import os assert get_obj_attr_tuple('os.path.exists') == (os.path, 'exists') def testOsPathExistsNot(self): import os assert get_obj_attr_tuple('os.path.exists.not') == ( os.path.exists, 'not') def testDisallowRelativeImports(self): with pytest.raises(TypeError): get_obj('.mum') mockito-python-1.2.2/tests/matchers_test.py000066400000000000000000000174751372607637100211130ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from .test_base import TestBase from mockito import mock, verify from mockito.matchers import and_, or_, not_, eq, neq, lt, lte, gt, gte, \ any_, arg_that, contains, matches, captor, ANY, ARGS, KWARGS import re class TestConvenienceMatchers: def testBuiltinAnyStandsForOurAny(self): dummy = mock() dummy.foo(1) dummy.foo('a') dummy.foo(True) verify(dummy, times=3).foo(any) dummy.foo(a=12) verify(dummy).foo(a=any) def testOurAnyCanBeUsedAsAType(self): dummy = mock() dummy.foo(1) dummy.foo('a') dummy.foo(True) verify(dummy, times=3).foo(any_) class TestAliases: def testANY(self): dummy = mock() dummy.foo(1) verify(dummy).foo(ANY) def testARGS(self): dummy = mock() dummy.foo(1) verify(dummy).foo(*ARGS) def testKWARGS(self): dummy = mock() dummy.foo(a=1) verify(dummy).foo(**KWARGS) class MatchersTest(TestBase): def testVerifiesUsingContainsMatcher(self): ourMock = mock() ourMock.foo("foobar") verify(ourMock).foo(contains("foo")) verify(ourMock).foo(contains("bar")) class AndMatcherTest(TestBase): def testShouldSatisfyIfAllMatchersAreSatisfied(self): self.assertTrue( and_(contains("foo"), contains("bar")).matches("foobar")) def testShouldNotSatisfyIfOneOfMatchersIsNotSatisfied(self): self.assertFalse( and_(contains("foo"), contains("bam")).matches("foobar")) def testShouldTreatNonMatchersAsEqMatcher(self): self.assertTrue(and_("foo", any_(str)).matches("foo")) self.assertFalse(and_("foo", any_(int)).matches("foo")) class OrMatcherTest(TestBase): def testShouldSatisfyIfAnyOfMatchersIsSatisfied(self): self.assertTrue( or_(contains("foo"), contains("bam")).matches("foobar")) def testShouldNotSatisfyIfAllOfMatchersAreNotSatisfied(self): self.assertFalse( or_(contains("bam"), contains("baz")).matches("foobar")) def testShouldTreatNonMatchersAsEqMatcher(self): self.assertTrue(or_("foo", "bar").matches("foo")) self.assertFalse(or_("foo", "bar").matches("bam")) class NotMatcherTest(TestBase): def testShouldSatisfyIfInnerMatcherIsNotSatisfied(self): self.assertTrue(not_(contains("foo")).matches("bar")) def testShouldNotSatisfyIfInnerMatcherIsSatisfied(self): self.assertFalse(not_(contains("foo")).matches("foo")) def testShouldTreatNonMatchersAsEqMatcher(self): self.assertTrue(or_("foo", "bar").matches("foo")) class EqMatcherTest(TestBase): def testShouldSatisfyIfArgMatchesGivenValue(self): self.assertTrue(eq("foo").matches("foo")) def testShouldNotSatisfyIfArgDoesNotMatchGivenValue(self): self.assertFalse(eq("foo").matches("bar")) class NeqMatcherTest(TestBase): def testShouldSatisfyIfArgDoesNotMatchGivenValue(self): self.assertTrue(neq("foo").matches("bar")) def testShouldNotSatisfyIfArgMatchesGivenValue(self): self.assertFalse(neq("foo").matches("foo")) class LtMatcherTest(TestBase): def testShouldSatisfyIfArgIsLessThanGivenValue(self): self.assertTrue(lt(5).matches(4)) def testShouldNotSatisfyIfArgIsEqualToGivenValue(self): self.assertFalse(lt(5).matches(5)) def testShouldNotSatisfyIfArgIsGreaterThanGivenValue(self): self.assertFalse(lt(5).matches(6)) class LteMatcherTest(TestBase): def testShouldSatisfyIfArgIsLessThanGivenValue(self): self.assertTrue(lte(5).matches(4)) def testShouldSatisfyIfArgIsEqualToGivenValue(self): self.assertTrue(lte(5).matches(5)) def testShouldNotSatisfyIfArgIsGreaterThanGivenValue(self): self.assertFalse(lte(5).matches(6)) class GtMatcherTest(TestBase): def testShouldNotSatisfyIfArgIsLessThanGivenValue(self): self.assertFalse(gt(5).matches(4)) def testShouldNotSatisfyIfArgIsEqualToGivenValue(self): self.assertFalse(gt(5).matches(5)) def testShouldSatisfyIfArgIsGreaterThanGivenValue(self): self.assertTrue(gt(5).matches(6)) class GteMatcherTest(TestBase): def testShouldNotSatisfyIfArgIsLessThanGivenValue(self): self.assertFalse(gte(5).matches(4)) def testShouldSatisfyIfArgIsEqualToGivenValue(self): self.assertTrue(gte(5).matches(5)) def testShouldSatisfyIfArgIsGreaterThanGivenValue(self): self.assertTrue(gte(5).matches(6)) class ArgThatMatcherTest(TestBase): def testShouldSatisfyIfPredicateReturnsTrue(self): self.assertTrue(arg_that(lambda arg: arg > 5).matches(10)) def testShouldNotSatisfyIfPredicateReturnsFalse(self): self.assertFalse(arg_that(lambda arg: arg > 5).matches(1)) class ContainsMatcherTest(TestBase): def testShouldSatisfiySubstringOfGivenString(self): self.assertTrue(contains("foo").matches("foobar")) def testShouldSatisfySameString(self): self.assertTrue(contains("foobar").matches("foobar")) def testShouldNotSatisfiyStringWhichIsNotSubstringOfGivenString(self): self.assertFalse(contains("barfoo").matches("foobar")) def testShouldNotSatisfiyEmptyString(self): self.assertFalse(contains("").matches("foobar")) def testShouldNotSatisfiyNone(self): self.assertFalse(contains(None).matches("foobar")) class MatchesMatcherTest(TestBase): def testShouldSatisfyIfRegexMatchesGivenString(self): self.assertTrue(matches('f..').matches('foo')) def testShouldAllowSpecifyingRegexFlags(self): self.assertFalse(matches('f..').matches('Foo')) self.assertTrue(matches('f..', re.IGNORECASE).matches('Foo')) def testShouldNotSatisfyIfRegexIsNotMatchedByGivenString(self): self.assertFalse(matches('f..').matches('bar')) class ArgumentCaptorTest(TestBase): def testShouldSatisfyIfInnerMatcherIsSatisfied(self): c = captor(contains("foo")) self.assertTrue(c.matches("foobar")) def testShouldNotSatisfyIfInnerMatcherIsNotSatisfied(self): c = captor(contains("foo")) self.assertFalse(c.matches("barbam")) def testShouldReturnNoneValueByDefault(self): c = captor(contains("foo")) self.assertEqual(None, c.value) def testShouldReturnNoneValueIfDidntMatch(self): c = captor(contains("foo")) c.matches("bar") self.assertEqual(None, c.value) def testShouldReturnLastMatchedValue(self): c = captor(contains("foo")) c.matches("foobar") c.matches("foobam") c.matches("bambaz") self.assertEqual("foobam", c.value) def testShouldDefaultMatcherToAny(self): c = captor() c.matches("foo") c.matches(123) self.assertEqual(123, c.value) mockito-python-1.2.2/tests/mocking_properties_test.py000066400000000000000000000020601372607637100231700ustar00rootroot00000000000000import pytest from mockito import mock, when def test_deprecated_a(unstub): # Setting on `__class__` is confusing for users m = mock() prop = mock() when(prop).__get__(Ellipsis).thenRaise(ValueError) m.__class__.tx = prop with pytest.raises(ValueError): m.tx def test_deprecated_b(unstub): # Setting on `__class__` is confusing for users m = mock() def _raise(*a): print(a) raise ValueError('Boom') m.__class__.tx = property(_raise) with pytest.raises(ValueError): m.tx def test_deprecated_c(unstub): # Setting on `__class__` is confusing for users # Wrapping explicitly with `property` as well m = mock() prop = mock(strict=True) when(prop).__call__(Ellipsis).thenRaise(ValueError) m.__class__.tx = property(prop) with pytest.raises(ValueError): m.tx def test_recommended_approach(): prop = mock(strict=True) when(prop).__get__(Ellipsis).thenRaise(ValueError) m = mock({'tx': prop}) with pytest.raises(ValueError): m.tx mockito-python-1.2.2/tests/module.py000066400000000000000000000001321372607637100175110ustar00rootroot00000000000000 class Foo(object): def no_arg(self): pass def one_arg(arg): return arg mockito-python-1.2.2/tests/modulefunctions_test.py000066400000000000000000000071331372607637100225110ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import os from .test_base import TestBase from mockito import when, unstub, verify, any from mockito.invocation import InvocationError from mockito.verification import VerificationError class ModuleFunctionsTest(TestBase): def tearDown(self): unstub() def testUnstubs(self): when(os.path).exists("test").thenReturn(True) unstub() self.assertEqual(False, os.path.exists("test")) def testStubs(self): when(os.path).exists("test").thenReturn(True) self.assertEqual(True, os.path.exists("test")) def testStubsConsecutiveCalls(self): when(os.path).exists("test").thenReturn(False).thenReturn(True) self.assertEqual(False, os.path.exists("test")) self.assertEqual(True, os.path.exists("test")) def testStubsMultipleClasses(self): when(os.path).exists("test").thenReturn(True) when(os.path).dirname(any(str)).thenReturn("mocked") self.assertEqual(True, os.path.exists("test")) self.assertEqual("mocked", os.path.dirname("whoah!")) def testVerifiesSuccesfully(self): when(os.path).exists("test").thenReturn(True) os.path.exists("test") verify(os.path).exists("test") def testFailsVerification(self): when(os.path).exists("test").thenReturn(True) self.assertRaises(VerificationError, verify(os.path).exists, "test") def testFailsOnNumberOfCalls(self): when(os.path).exists("test").thenReturn(True) os.path.exists("test") self.assertRaises(VerificationError, verify(os.path, times=2).exists, "test") def testStubsTwiceAndUnstubs(self): when(os.path).exists("test").thenReturn(False) when(os.path).exists("test").thenReturn(True) self.assertEqual(True, os.path.exists("test")) unstub() self.assertEqual(False, os.path.exists("test")) def testStubsTwiceWithDifferentArguments(self): when(os.path).exists("Foo").thenReturn(False) when(os.path).exists("Bar").thenReturn(True) self.assertEqual(False, os.path.exists("Foo")) self.assertEqual(True, os.path.exists("Bar")) def testShouldThrowIfWeStubAFunctionNotDefinedInTheModule(self): self.assertRaises(InvocationError, lambda: when(os).walk_the_line().thenReturn(None)) def testEnsureWeCanMockTheClassOnAModule(self): from . import module when(module).Foo().thenReturn('mocked') assert module.Foo() == 'mocked' mockito-python-1.2.2/tests/my_dict_test.py000066400000000000000000000022521372607637100207200ustar00rootroot00000000000000 import pytest from mockito.mock_registry import _Dict from mockito.mocking import Mock class TestCustomDictLike: def testAssignKeyValuePair(self): td = _Dict() obj = {} mock = Mock(None) td[obj] = mock def testGetValueForKey(self): td = _Dict() obj = {} mock = Mock(None) td[obj] = mock assert td.get(obj) == mock def testReplaceValueForSameKey(self): td = _Dict() obj = {} mock1 = Mock(None) mock2 = Mock(None) td[obj] = mock1 td[obj] = mock2 assert td.pop(obj) == mock2 with pytest.raises(KeyError): td.pop(obj) def testPopKey(self): td = _Dict() obj = {} mock = Mock(None) td[obj] = mock assert td.pop(obj) == mock assert td.get(obj) is None def testIterValues(self): td = _Dict() obj = {} mock = Mock(None) td[obj] = mock assert td.values() == [mock] def testClear(self): td = _Dict() obj = {} mock = Mock(None) td[obj] = mock td.clear() assert td.get(obj) is None mockito-python-1.2.2/tests/numpy_test.py000066400000000000000000000014141372607637100204370ustar00rootroot00000000000000import mockito from mockito import when, patch import pytest import numpy as np from . import module pytestmark = pytest.mark.usefixtures("unstub") def xcompare(a, b): if isinstance(a, mockito.matchers.Matcher): return a.matches(b) return np.array_equal(a, b) class TestEnsureNumpyWorks: def testEnsureNumpyArrayAllowedWhenStubbing(self): array = np.array([1, 2, 3]) when(module).one_arg(array).thenReturn('yep') with patch(mockito.invocation.MatchingInvocation.compare, xcompare): assert module.one_arg(array) == 'yep' def testEnsureNumpyArrayAllowedWhenCalling(self): array = np.array([1, 2, 3]) when(module).one_arg(Ellipsis).thenReturn('yep') assert module.one_arg(array) == 'yep' mockito-python-1.2.2/tests/signatures_test.py000066400000000000000000000253161372607637100214620ustar00rootroot00000000000000 import pytest from mockito import when, args, kwargs, unstub from collections import namedtuple class CallSignature(namedtuple('CallSignature', 'args kwargs')): def raises(self, reason): return pytest.mark.xfail(self, raises=reason, strict=True) def sig(*a, **kw): return CallSignature(a, kw) class SUT(object): def none_args(self): pass def one_arg(self, a): pass def two_args(self, a, b): pass def star_arg(self, *args): pass def star_kwarg(self, **kwargs): pass def arg_plus_star_arg(self, a, *b): pass def arg_plus_star_kwarg(self, a, **b): pass def two_args_wt_default(self, a, b=None): pass def combination(self, a, b=None, *c, **d): pass class ClassMethods(object): @classmethod def none_args(cls): pass @classmethod def one_arg(cls, a): pass @classmethod def two_args(cls, a, b): pass @classmethod def star_arg(cls, *a): pass @classmethod def star_kwarg(cls, **kw): pass @classmethod def arg_plus_star_arg(cls, a, *b): pass @classmethod def arg_plus_star_kwarg(cls, a, **b): pass @classmethod def two_args_wt_default(cls, a, b=None): pass @classmethod def combination(cls, a, b=None, *c, **d): pass class StaticMethods(object): @staticmethod def none_args(): pass @staticmethod def one_arg(a): pass @staticmethod def two_args(a, b): pass @staticmethod def star_arg(*a): pass @staticmethod def star_kwarg(**kw): pass @staticmethod def arg_plus_star_arg(a, *b): pass @staticmethod def arg_plus_star_kwarg(a, **b): pass @staticmethod def two_args_wt_default(a, b=None): pass @staticmethod def combination(a, b=None, *c, **d): pass @pytest.fixture(params=[ 'instance', 'class', 'classmethods', 'staticmethods', 'staticmethods_2', ]) def sut(request): if request.param == 'instance': yield SUT() elif request.param == 'class': yield SUT elif request.param == 'classmethods': yield ClassMethods elif request.param == 'staticmethods': yield StaticMethods elif request.param == 'staticmethods_2': yield StaticMethods() unstub() class TestSignatures: class TestNoneArg: @pytest.mark.parametrize('call', [ sig(), sig(Ellipsis), ]) def test_passing(self, sut, call): when(sut).none_args(*call.args, **call.kwargs).thenReturn('stub') @pytest.mark.parametrize('call', [ sig(12), sig(*args), sig(**kwargs), sig(*args, **kwargs) ]) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).none_args(*call.args, **call.kwargs) class TestOneArg: @pytest.mark.parametrize('call', [ sig(12), sig(a=12), sig(Ellipsis), sig(*args), sig(*args, **kwargs), sig(**kwargs), ]) def test_passing(self, sut, call): when(sut).one_arg(*call.args, **call.kwargs).thenReturn('stub') @pytest.mark.parametrize('call', [ sig(12, 13), sig(12, b=2), sig(12, 13, 14), sig(b=2), sig(12, c=2), sig(12, b=2, c=2), sig(12, Ellipsis), sig(1, *args), sig(*args, a=1), sig(*args, b=1), sig(1, **kwargs), ]) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).one_arg(*call.args, **call.kwargs) class TestTwoArgs: # def two_args(a, b) @pytest.mark.parametrize('call', [ sig(12, 13), sig(12, b=2), sig(Ellipsis), sig(12, Ellipsis), sig(*args), sig(*args, **kwargs), sig(12, *args), sig(**kwargs), sig(12, **kwargs), sig(b=13, **kwargs), ]) def test_passing(self, sut, call): when(sut).two_args(*call.args, **call.kwargs) @pytest.mark.parametrize('call', [ sig(12), sig(12, 13, 14), sig(b=2), sig(12, c=2), sig(12, b=2, c=2), sig(12, 13, Ellipsis), sig(12, 13, *args), sig(12, b=13, *args), sig(12, 13, **kwargs), sig(12, b=13, **kwargs), ]) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).two_args(*call.args, **call.kwargs) class TestStarArg: # def star_arg(*args) @pytest.mark.parametrize('call', [ sig(), sig(12), sig(12, 13), sig(Ellipsis), sig(12, Ellipsis), sig(12, 13, Ellipsis), sig(*args), sig(12, *args), sig(12, 13, *args) ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).star_arg(*call.args, **call.kwargs) @pytest.mark.parametrize('call', [ sig(**kwargs), sig(12, **kwargs), sig(Ellipsis, **kwargs), sig(a=12), sig(args=12) ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).star_arg(*call.args, **call.kwargs) class TestStarKwarg: # def star_kwarg(**kwargs) @pytest.mark.parametrize('call', [ sig(), sig(a=1), sig(a=1, b=2), sig(Ellipsis), sig(**kwargs), sig(a=1, **kwargs) ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).star_kwarg(*call.args, **call.kwargs) @pytest.mark.parametrize('call', [ sig(12), sig(*args), sig(*args, **kwargs), sig(12, a=1) ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).star_kwarg(*call.args, **call.kwargs) class TestArgPlusStarArg: # def arg_plus_star_arg(a, *args) @pytest.mark.parametrize('call', [ sig(12), sig(a=12), sig(12, 13), sig(Ellipsis), sig(12, Ellipsis), sig(12, 13, Ellipsis), sig(*args), sig(12, *args), sig(**kwargs), ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).arg_plus_star_arg(*call.args, **call.kwargs) @pytest.mark.parametrize('call', [ sig(), sig(13, a=12), sig(b=13), sig(12, b=13, *args), sig(a=12, b=13, *args), sig(12, **kwargs), sig(a=12, **kwargs), ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).arg_plus_star_arg(*call.args, **call.kwargs) class TestArgPlusStarKwarg: # def arg_plus_star_kwarg(a, **kwargs) @pytest.mark.parametrize('call', [ sig(12), sig(a=12), sig(12, b=1), sig(Ellipsis), sig(12, Ellipsis), sig(**kwargs), sig(12, **kwargs), sig(a=12, **kwargs), sig(12, b=1, **kwargs), sig(a=12, b=1, **kwargs), sig(*args), sig(*args, b=1), sig(*args, **kwargs) ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).arg_plus_star_kwarg(*call.args, **call.kwargs) @pytest.mark.parametrize('call', [ sig(), sig(12, 13), sig(b=1), sig(12, a=1), sig(12, 13, Ellipsis), sig(*args, a=1), sig(12, *args) ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).arg_plus_star_kwarg(*call.args, **call.kwargs) class TestTwoArgsWtDefault: @pytest.mark.parametrize('call', [ sig(12), sig(12, 13), sig(12, b=2), sig(Ellipsis), sig(12, Ellipsis), sig(*args), sig(*args, **kwargs), sig(12, *args), sig(*args, b=2), sig(**kwargs), sig(12, **kwargs), ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).two_args_wt_default( *call.args, **call.kwargs).thenReturn() @pytest.mark.parametrize('call', [ sig(12, 13, 14), sig(b=2), sig(12, c=2), sig(12, b=2, c=2), sig(12, 13, Ellipsis), sig(12, 13, *args), sig(12, b=13, *args), sig(12, c=13, *args), sig(12, *args, b=2), sig(*args, a=2), sig(*args, c=2), sig(12, 13, **kwargs), sig(12, b=13, **kwargs), sig(12, c=13, **kwargs), ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).two_args_wt_default( *call.args, **call.kwargs).thenReturn() class TestCombination: # def combination(self, a, b=None, *c, **d) @pytest.mark.parametrize('call', [ sig(12), sig(12, 13), sig(12, 13, 14), sig(12, 13, 14, 15), sig(Ellipsis), sig(12, Ellipsis), sig(12, 13, Ellipsis), sig(12, 13, 14, Ellipsis), sig(12, 13, 14, 15, Ellipsis) ], ids=lambda i: str(i)) def test_passing(self, sut, call): when(sut).combination( *call.args, **call.kwargs).thenReturn() @pytest.mark.parametrize('call', [ sig(12, 13, b=16), ], ids=lambda i: str(i)) def test_failing(self, sut, call): with pytest.raises(TypeError): when(sut).combination( *call.args, **call.kwargs).thenReturn() class TestBuiltin: def testBuiltinOpen(self): try: import builtins except ImportError: import __builtin__ as builtins try: when(builtins).open('foo') finally: # just to be sure unstub() mockito-python-1.2.2/tests/speccing_test.py000066400000000000000000000064471372607637100210750ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from mockito.invocation import InvocationError from mockito import mock, when, verify class Foo(object): def bar(self): pass class Action(object): def no_arg(self): pass def run(self, arg): return arg def __call__(self, task): return task class TestSpeccing: def testStubCallAndVerify(self): action = mock(Action) when(action).run(11).thenReturn(12) assert action.run(11) == 12 verify(action).run(11) def testShouldScreamWhenStubbingUnknownMethod(self): action = mock(Action) with pytest.raises(InvocationError): when(action).unknownMethod() def testShouldScreamWhenCallingUnknownMethod(self): action = mock(Action) with pytest.raises(AttributeError): action.unknownMethod() def testShouldScreamWhenCallingUnexpectedMethod(self): action = mock(Action) with pytest.raises(AttributeError): action.run(11) def testPreconfigureMockWithAttributes(self): action = mock({'foo': 'bar'}, spec=Action) assert action.foo == 'bar' with pytest.raises(InvocationError): when(action).remember() def testPreconfigureWithFunction(self): action = mock({ 'run': lambda _: 12 }, spec=Action) assert action.run(11) == 12 verify(action).run(11) def testPreconfigureWithFunctionThatTakesNoArgs(self): action = mock({ 'no_arg': lambda: 12 }, spec=Action) assert action.no_arg() == 12 verify(action).no_arg() def testShouldScreamOnUnknownAttribute(self): action = mock(Action) with pytest.raises(AttributeError): action.cam def testShouldPassIsInstanceChecks(self): action = mock(Action) assert isinstance(action, Action) def testHasANiceName(self): action = mock(Action) assert repr(action) == "" % id(action) class TestSpeccingLoose: def testReturnNoneForEveryMethod(self): action = mock(Action, strict=False) assert action.unknownMethod() is None assert action.run(11) is None mockito-python-1.2.2/tests/spying_test.py000066400000000000000000000110371372607637100206020ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest import sys from .test_base import TestBase from mockito import ( when, spy, spy2, verify, VerificationError, verifyZeroInteractions) import time class Dummy(object): def foo(self): return "foo" def bar(self): raise TypeError def return_args(self, *args, **kwargs): return (args, kwargs) @classmethod def class_method(cls, arg): return arg class SpyingTest(TestBase): def testPreservesReturnValues(self): dummy = Dummy() spiedDummy = spy(dummy) self.assertEqual(dummy.foo(), spiedDummy.foo()) def testPreservesSideEffects(self): dummy = spy(Dummy()) self.assertRaises(TypeError, dummy.bar) def testPassesArgumentsCorrectly(self): dummy = spy(Dummy()) self.assertEqual((('foo', 1), {'bar': 'baz'}), dummy.return_args('foo', 1, bar='baz')) def testIsVerifiable(self): dummy = spy(Dummy()) dummy.foo() verify(dummy).foo() self.assertRaises(VerificationError, verify(dummy).bar) def testVerifyZeroInteractionsWorks(self): dummy = spy(Dummy()) verifyZeroInteractions(dummy) def testRaisesAttributeErrorIfNoSuchMethod(self): original = Dummy() dummy = spy(original) try: dummy.lol() self.fail("Should fail if no such method.") except AttributeError as e: self.assertEqual("You tried to call method 'lol' which '%s' " "instance does not have." % original, str(e)) def testIsInstanceFakesOriginalClass(self): dummy = spy(Dummy()) assert isinstance(dummy, Dummy) def testHasNiceRepr(self): dummy = spy(Dummy()) assert repr(dummy) == "" % id(dummy) def testCallClassmethod(self): dummy = spy(Dummy) assert dummy.class_method('foo') == 'foo' verify(dummy).class_method('foo') @pytest.mark.xfail( sys.version_info >= (3,), reason="python3 allows any value for self" ) def testCantCallInstanceMethodWhenSpyingClass(self): dummy = spy(Dummy) with pytest.raises(TypeError): dummy.return_args('foo') def testModuleFunction(self): import time dummy = spy(time) assert dummy.time() is not None verify(dummy).time() class TestSpy2: def testA(self): dummy = Dummy() spy2(dummy.foo) assert dummy.foo() == 'foo' verify(dummy).foo() def testB(self): spy2(Dummy.class_method) assert Dummy.class_method('foo') == 'foo' verify(Dummy).class_method('foo') def testModule(self): spy2(time.time) assert time.time() is not None verify(time).time() def testEnsureStubbedResponseForSpecificInvocation(self): dummy = Dummy() spy2(dummy.return_args) when(dummy).return_args('foo').thenReturn('fox') assert dummy.return_args('bar') == (('bar',), {}) assert dummy.return_args('box') == (('box',), {}) assert dummy.return_args('foo') == 'fox' def testEnsureStubOrder(self): dummy = Dummy() when(dummy).return_args(Ellipsis).thenReturn('foo') when(dummy).return_args('fox').thenReturn('fix') assert dummy.return_args('bar') == 'foo' assert dummy.return_args('box') == 'foo' assert dummy.return_args('fox') == 'fix' mockito-python-1.2.2/tests/staticmethods_test.py000066400000000000000000000107001372607637100221400ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from .test_base import TestBase from mockito import when, verify, unstub, any from mockito.verification import VerificationError class Dog: @staticmethod def bark(): return "woof" @staticmethod def barkHardly(*args): return "woof woof" class Cat: @staticmethod def meow(): return "miau" class StaticMethodsTest(TestBase): def tearDown(self): unstub() def testUnstubs(self): when(Dog).bark().thenReturn("miau") unstub() self.assertEqual("woof", Dog.bark()) # TODO decent test case please :) without testing irrelevant implementation # details def testUnstubShouldPreserveMethodType(self): when(Dog).bark().thenReturn("miau!") unstub() self.assertTrue(isinstance(Dog.__dict__.get("bark"), staticmethod)) def testStubs(self): self.assertEqual("woof", Dog.bark()) when(Dog).bark().thenReturn("miau") self.assertEqual("miau", Dog.bark()) def testStubsConsecutiveCalls(self): when(Dog).bark().thenReturn(1).thenReturn(2) self.assertEqual(1, Dog.bark()) self.assertEqual(2, Dog.bark()) self.assertEqual(2, Dog.bark()) def testStubsWithArgs(self): self.assertEqual("woof woof", Dog.barkHardly(1, 2)) when(Dog).barkHardly(1, 2).thenReturn("miau") self.assertEqual("miau", Dog.barkHardly(1, 2)) def testStubsButDoesNotMachArguments(self): self.assertEqual("woof woof", Dog.barkHardly(1, "anything")) when(Dog, strict=False).barkHardly(1, 2).thenReturn("miau") self.assertEqual(None, Dog.barkHardly(1)) def testStubsMultipleClasses(self): when(Dog).barkHardly(1, 2).thenReturn(1) when(Dog).bark().thenReturn(2) when(Cat).meow().thenReturn(3) self.assertEqual(1, Dog.barkHardly(1, 2)) self.assertEqual(2, Dog.bark()) self.assertEqual(3, Cat.meow()) unstub() self.assertEqual("woof", Dog.bark()) self.assertEqual("miau", Cat.meow()) def testVerifiesSuccesfully(self): when(Dog).bark().thenReturn("boo") Dog.bark() verify(Dog).bark() def testVerifiesWithArguments(self): when(Dog).barkHardly(1, 2).thenReturn("boo") Dog.barkHardly(1, 2) verify(Dog).barkHardly(1, any()) def testFailsVerification(self): when(Dog).bark().thenReturn("boo") Dog.bark() self.assertRaises(VerificationError, verify(Dog).barkHardly, (1, 2)) def testFailsOnInvalidArguments(self): when(Dog).bark().thenReturn("boo") Dog.barkHardly(1, 2) self.assertRaises(VerificationError, verify(Dog).barkHardly, (1, 20)) def testFailsOnNumberOfCalls(self): when(Dog).bark().thenReturn("boo") Dog.bark() self.assertRaises(VerificationError, verify(Dog, times=2).bark) def testStubsAndVerifies(self): when(Dog).bark().thenReturn("boo") self.assertEqual("boo", Dog.bark()) verify(Dog).bark() def testStubsTwiceAndUnstubs(self): when(Dog).bark().thenReturn(1) when(Dog).bark().thenReturn(2) self.assertEqual(2, Dog.bark()) unstub() self.assertEqual("woof", Dog.bark()) def testDoesNotVerifyStubbedCalls(self): when(Dog).bark().thenReturn(1) verify(Dog, times=0).bark() mockito-python-1.2.2/tests/stubbing_test.py000066400000000000000000000325701372607637100211130ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from .test_base import TestBase from mockito import mock, when, verify, times, any class TestEmptyMocks: def testAllMethodsReturnNone(self): dummy = mock() assert dummy.foo() is None assert dummy.foo(1, 2) is None def testConfigureDummy(self): dummy = mock({'foo': 'bar'}) assert dummy.foo == 'bar' def testConfigureDummyWithFunction(self): dummy = mock({ 'getStuff': lambda s: s + ' thing' }) assert dummy.getStuff('da') == 'da thing' verify(dummy).getStuff('da') def testDummiesAreCallable(self): dummy = mock() assert dummy() is None assert dummy(1, 2) is None def testCallsAreVerifiable(self): dummy = mock() dummy(1, 2) verify(dummy).__call__(1, 2) def testConfigureCallBehavior(self): dummy = mock() when(dummy).__call__(1).thenReturn(2) assert dummy(1) == 2 verify(dummy).__call__(1) def testCheckIsInstanceAgainstItself(self): dummy = mock() assert isinstance(dummy, dummy.__class__) def testConfigureMagicMethod(self): dummy = mock() when(dummy).__getitem__(1).thenReturn(2) assert dummy[1] == 2 class TestStrictEmptyMocks: def testScream(self): dummy = mock(strict=True) with pytest.raises(AttributeError): dummy.foo() def testAllowStubbing(self): dummy = mock(strict=True) when(dummy).foo() dummy.foo() verify(dummy).foo() def testCanConfigureCall(self): dummy = mock(strict=True) when(dummy).__call__(1).thenReturn(2) assert dummy(1) == 2 def testScreamOnUnconfiguredCall(self): dummy = mock(strict=True) with pytest.raises(AttributeError): dummy(1) def testConfigureMagicMethod(self): dummy = mock(strict=True) when(dummy).__getitem__(1).thenReturn(2) assert dummy[1] == 2 class StubbingTest(TestBase): def testStubsWithReturnValue(self): theMock = mock() when(theMock).getStuff().thenReturn("foo") when(theMock).getMoreStuff(1, 2).thenReturn(10) self.assertEqual("foo", theMock.getStuff()) self.assertEqual(10, theMock.getMoreStuff(1, 2)) self.assertEqual(None, theMock.getMoreStuff(1, 3)) def testStubsWhenNoArgsGiven(self): theMock = mock() when(theMock).getStuff().thenReturn("foo") when(theMock).getWidget().thenReturn("bar") self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getWidget()) def testStubsConsecutivelyWhenNoArgsGiven(self): theMock = mock() when(theMock).getStuff().thenReturn("foo").thenReturn("bar") when(theMock).getWidget().thenReturn("baz").thenReturn("baz2") self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertEqual("baz", theMock.getWidget()) self.assertEqual("baz2", theMock.getWidget()) self.assertEqual("baz2", theMock.getWidget()) def testStubsWithException(self): theMock = mock() when(theMock).someMethod().thenRaise(Exception("foo")) self.assertRaisesMessage("foo", theMock.someMethod) def testStubsAndVerifies(self): theMock = mock() when(theMock).foo().thenReturn("foo") self.assertEqual("foo", theMock.foo()) verify(theMock).foo() def testStubsVerifiesAndStubsAgain(self): theMock = mock() when(theMock).foo().thenReturn("foo") self.assertEqual("foo", theMock.foo()) verify(theMock).foo() when(theMock).foo().thenReturn("next foo") self.assertEqual("next foo", theMock.foo()) verify(theMock, times(2)).foo() def testOverridesStubbing(self): theMock = mock() when(theMock).foo().thenReturn("foo") when(theMock).foo().thenReturn("bar") self.assertEqual("bar", theMock.foo()) def testStubsAndInvokesTwiceAndVerifies(self): theMock = mock() when(theMock).foo().thenReturn("foo") self.assertEqual("foo", theMock.foo()) self.assertEqual("foo", theMock.foo()) verify(theMock, times(2)).foo() def testStubsAndReturnValuesForSameMethodWithDifferentArguments(self): theMock = mock() when(theMock).getStuff(1).thenReturn("foo") when(theMock).getStuff(1, 2).thenReturn("bar") self.assertEqual("foo", theMock.getStuff(1)) self.assertEqual("bar", theMock.getStuff(1, 2)) def testStubsAndReturnValuesForSameMethodWithDifferentNamedArguments(self): repo = mock() when(repo).findby(id=6).thenReturn("John May") when(repo).findby(name="John").thenReturn(["John May", "John Smith"]) self.assertEqual("John May", repo.findby(id=6)) self.assertEqual(["John May", "John Smith"], repo.findby(name="John")) def testStubsForMethodWithSameNameAndNamedArgumentsInArbitraryOrder(self): theMock = mock() when(theMock).foo(first=1, second=2, third=3).thenReturn(True) self.assertEqual(True, theMock.foo(third=3, first=1, second=2)) def testStubsMethodWithSameNameAndMixedArguments(self): repo = mock() when(repo).findby(1).thenReturn("John May") when(repo).findby(1, active_only=True).thenReturn(None) when(repo).findby(name="Sarah").thenReturn(["Sarah Connor"]) when(repo).findby(name="Sarah", active_only=True).thenReturn([]) self.assertEqual("John May", repo.findby(1)) self.assertEqual(None, repo.findby(1, active_only=True)) self.assertEqual(["Sarah Connor"], repo.findby(name="Sarah")) self.assertEqual([], repo.findby(name="Sarah", active_only=True)) def testStubsWithChainedReturnValues(self): theMock = mock() when(theMock).getStuff().thenReturn("foo") \ .thenReturn("bar") \ .thenReturn("foobar") self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertEqual("foobar", theMock.getStuff()) def testStubsWithChainedReturnValuesAndException(self): theMock = mock() when(theMock).getStuff().thenReturn("foo") \ .thenReturn("bar") \ .thenRaise(Exception("foobar")) self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertRaisesMessage("foobar", theMock.getStuff) def testStubsWithChainedExceptionAndReturnValue(self): theMock = mock() when(theMock).getStuff().thenRaise(Exception("foo")) \ .thenReturn("bar") self.assertRaisesMessage("foo", theMock.getStuff) self.assertEqual("bar", theMock.getStuff()) def testStubsWithChainedExceptions(self): theMock = mock() when(theMock).getStuff().thenRaise(Exception("foo")) \ .thenRaise(Exception("bar")) self.assertRaisesMessage("foo", theMock.getStuff) self.assertRaisesMessage("bar", theMock.getStuff) def testStubsWithReturnValueBeingException(self): theMock = mock() exception = Exception("foo") when(theMock).getStuff().thenReturn(exception) self.assertEqual(exception, theMock.getStuff()) def testLastStubbingWins(self): theMock = mock() when(theMock).foo().thenReturn(1) when(theMock).foo().thenReturn(2) self.assertEqual(2, theMock.foo()) def testStubbingOverrides(self): theMock = mock() when(theMock).foo().thenReturn(1) when(theMock).foo().thenReturn(2).thenReturn(3) self.assertEqual(2, theMock.foo()) self.assertEqual(3, theMock.foo()) self.assertEqual(3, theMock.foo()) def testStubsWithMatchers(self): theMock = mock() when(theMock).foo(any()).thenReturn(1) self.assertEqual(1, theMock.foo(1)) self.assertEqual(1, theMock.foo(100)) def testStubbingOverrides2(self): theMock = mock() when(theMock).foo(any()).thenReturn(1) when(theMock).foo("oh").thenReturn(2) self.assertEqual(2, theMock.foo("oh")) self.assertEqual(1, theMock.foo("xxx")) def testDoesNotVerifyStubbedCalls(self): theMock = mock() when(theMock).foo().thenReturn(1) verify(theMock, times=0).foo() def testStubsWithMultipleReturnValues(self): theMock = mock() when(theMock).getStuff().thenReturn("foo", "bar", "foobar") self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertEqual("foobar", theMock.getStuff()) def testStubsWithChainedMultipleReturnValues(self): theMock = mock() when(theMock).getStuff().thenReturn("foo", "bar") \ .thenReturn("foobar") self.assertEqual("foo", theMock.getStuff()) self.assertEqual("bar", theMock.getStuff()) self.assertEqual("foobar", theMock.getStuff()) def testStubsWithMultipleExceptions(self): theMock = mock() when(theMock).getStuff().thenRaise(Exception("foo"), Exception("bar")) self.assertRaisesMessage("foo", theMock.getStuff) self.assertRaisesMessage("bar", theMock.getStuff) def testStubsWithMultipleChainedExceptions(self): theMock = mock() when(theMock).getStuff() \ .thenRaise(Exception("foo"), Exception("bar")) \ .thenRaise(Exception("foobar")) self.assertRaisesMessage("foo", theMock.getStuff) self.assertRaisesMessage("bar", theMock.getStuff) self.assertRaisesMessage("foobar", theMock.getStuff) def testLeavesOriginalMethodUntouchedWhenCreatingStubFromRealClass(self): class Person: def get_name(self): return "original name" # given person = Person() mockPerson = mock(Person) # when when(mockPerson).get_name().thenReturn("stubbed name") # then self.assertEqual("stubbed name", mockPerson.get_name()) self.assertEqual("original name", person.get_name(), 'Original method should not be replaced.') def testStubsWithThenAnswer(self): m = mock() when(m).magic_number().thenAnswer(lambda: 5) self.assertEqual(m.magic_number(), 5) when(m).add_one(any()).thenAnswer(lambda number: number + 1) self.assertEqual(m.add_one(5), 6) self.assertEqual(m.add_one(8), 9) when(m).do_times(any(), any()).thenAnswer(lambda one, two: one * two) self.assertEqual(m.do_times(5, 4), 20) self.assertEqual(m.do_times(8, 5), 40) when(m).do_dev_magic(any(), any()).thenAnswer(lambda a, b: a / b) self.assertEqual(m.do_dev_magic(20, 4), 5) self.assertEqual(m.do_dev_magic(40, 5), 8) def test_key_words(testing="Magic"): return testing + " Stuff" when(m).with_key_words().thenAnswer(test_key_words) self.assertEqual(m.with_key_words(), "Magic Stuff") when(m).with_key_words(testing=any()).thenAnswer(test_key_words) self.assertEqual(m.with_key_words(testing="Very Funky"), "Very Funky Stuff") def testSubsWithThenAnswerAndMixedArgs(self): repo = mock() def method_one(value, active_only=False): return None def method_two(name=None, active_only=False): return ["%s Connor" % name] def method_three(name=None, active_only=False): return [name, active_only, 0] when(repo).findby(1).thenAnswer(lambda x: "John May (%d)" % x) when(repo).findby(1, active_only=True).thenAnswer(method_one) when(repo).findby(name="Sarah").thenAnswer(method_two) when(repo).findby( name="Sarah", active_only=True).thenAnswer(method_three) self.assertEqual("John May (1)", repo.findby(1)) self.assertEqual(None, repo.findby(1, active_only=True)) self.assertEqual(["Sarah Connor"], repo.findby(name="Sarah")) self.assertEqual( ["Sarah", True, 0], repo.findby(name="Sarah", active_only=True)) mockito-python-1.2.2/tests/test_base.py000066400000000000000000000030411372607637100201770ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import unittest class TestBase(unittest.TestCase): def assertRaisesMessage(self, message, callable, *params): try: if (params): callable(params) else: callable() except Exception as e: self.assertEqual(message, str(e)) else: self.fail('Exception with message "%s" expected, but never raised' % (message)) mockito-python-1.2.2/tests/unstub_test.py000066400000000000000000000067541372607637100206230ustar00rootroot00000000000000import pytest from mockito import when, unstub, verify, ArgumentError class Dog(object): def waggle(self): return 'Unsure' def bark(self, sound='Wuff'): return sound class TestUntub: def testIndependentUnstubbing(self): rex = Dog() mox = Dog() when(rex).waggle().thenReturn('Yup') when(mox).waggle().thenReturn('Nope') assert rex.waggle() == 'Yup' assert mox.waggle() == 'Nope' unstub(rex) assert rex.waggle() == 'Unsure' assert mox.waggle() == 'Nope' unstub(mox) assert mox.waggle() == 'Unsure' class TestAutomaticUnstubbing: def testWith1(self): rex = Dog() with when(rex).waggle().thenReturn('Yup'): assert rex.waggle() == 'Yup' verify(rex).waggle() assert rex.waggle() == 'Unsure' def testWith2(self): # Ensure the short version to return None works rex = Dog() with when(rex).waggle(): assert rex.waggle() is None verify(rex).waggle() assert rex.waggle() == 'Unsure' def testWithRaisingSideeffect(self): rex = Dog() with pytest.raises(RuntimeError): with when(rex).waggle().thenRaise(RuntimeError('Nope')): rex.waggle() assert rex.waggle() == 'Unsure' def testNesting(self): # That's not a real test, I just wanted to see how it would # look like; bc you run out of space pretty quickly rex = Dog() mox = Dog() with when(rex).waggle().thenReturn('Yup'): with when(mox).waggle().thenReturn('Nope'): assert rex.waggle() == 'Yup' assert rex.waggle() == 'Unsure' assert mox.waggle() == 'Unsure' # though that's a good looking option with when(rex).waggle().thenReturn('Yup'), \ when(mox).waggle().thenReturn('Nope'): # noqa: E127 assert rex.waggle() == 'Yup' assert mox.waggle() == 'Nope' assert rex.waggle() == 'Unsure' assert mox.waggle() == 'Unsure' def testOnlyUnstubTheExactStub(self): rex = Dog() when(rex).bark('Shhh').thenReturn('Nope') with when(rex).bark('Miau').thenReturn('Grrr'): assert rex.bark('Miau') == 'Grrr' assert rex.bark('Shhh') == 'Nope' verify(rex, times=2).bark(Ellipsis) def testOnlyUnstubTheExcatMethod(self): rex = Dog() when(rex).bark('Shhh').thenReturn('Nope') with when(rex).waggle().thenReturn('Yup'): assert rex.waggle() == 'Yup' assert rex.bark('Shhh') == 'Nope' verify(rex, times=1).bark(Ellipsis) verify(rex, times=1).waggle() def testCleanupRegistryAfterLastStub(self): rex = Dog() with when(rex).bark('Shhh').thenReturn('Nope'): with when(rex).bark('Miau').thenReturn('Grrr'): assert rex.bark('Miau') == 'Grrr' assert rex.bark('Shhh') == 'Nope' with pytest.raises(ArgumentError): verify(rex).bark(Ellipsis) class TestEnsureCleanUnstubIfMockingAGlobal: def testA(self): with when(Dog).waggle().thenReturn('Sure'): rex = Dog() assert rex.waggle() == 'Sure' verify(Dog).waggle() def testB(self): with when(Dog).waggle().thenReturn('Sure'): rex = Dog() assert rex.waggle() == 'Sure' verify(Dog).waggle() mockito-python-1.2.2/tests/verification_errors_test.py000066400000000000000000000105261372607637100233510ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from mockito import (mock, when, verify, VerificationError, verifyNoMoreInteractions, verification) from mockito.verification import never class TestVerificationErrors: def testPrintsNicelyNothingIfNeverUsed(self): theMock = mock() with pytest.raises(VerificationError) as exc: verify(theMock).foo() assert str(exc.value) == ''' Wanted but not invoked: foo() Instead got: Nothing ''' def testPrintsNicely(self): theMock = mock() theMock.foo('bar') theMock.foo(12, baz='boz') with pytest.raises(VerificationError) as exc: verify(theMock).foo(True, None) assert str(exc.value) == ''' Wanted but not invoked: foo(True, None) Instead got: foo('bar') foo(12, baz='boz') ''' def testPrintOnlySameMethodInvocationsIfAny(self): theMock = mock() theMock.foo('bar') theMock.bar('foo') with pytest.raises(VerificationError) as exc: verify(theMock).bar('fox') assert str(exc.value) == ''' Wanted but not invoked: bar('fox') Instead got: bar('foo') ''' def testPrintAllInvocationsIfNoInvocationWithSameMethodName(self): theMock = mock() theMock.foo('bar') theMock.bar('foo') with pytest.raises(VerificationError) as exc: verify(theMock).box('fox') assert str(exc.value) == ''' Wanted but not invoked: box('fox') Instead got: foo('bar') bar('foo') ''' def testPrintKeywordArgumentsNicely(self): theMock = mock() with pytest.raises(VerificationError) as exc: verify(theMock).foo(foo='foo', one=1) message = str(exc.value) # We do not want to guarantee any order of arguments here assert "foo='foo'" in message assert "one=1" in message def testPrintsOutThatTheActualAndExpectedInvocationCountDiffers(self): theMock = mock() when(theMock).foo().thenReturn(0) theMock.foo() theMock.foo() with pytest.raises(VerificationError) as exc: verify(theMock).foo() assert "\nWanted times: 1, actual times: 2" == str(exc.value) def testPrintsUnwantedInteraction(self): theMock = mock() theMock.foo(1, 'foo') with pytest.raises(VerificationError) as exc: verifyNoMoreInteractions(theMock) assert "\nUnwanted interaction: foo(1, 'foo')" == str(exc.value) def testPrintsNeverWantedInteractionsNicely(self): theMock = mock() theMock.foo() with pytest.raises(VerificationError) as exc: verify(theMock, never).foo() assert "\nUnwanted invocation of foo(), times: 1" == str(exc.value) class TestReprOfVerificationClasses: def testTimes(self): times = verification.Times(1) assert repr(times) == "" def testAtLeast(self): atleast = verification.AtLeast(2) assert repr(atleast) == "" def testAtMost(self): atmost = verification.AtMost(3) assert repr(atmost) == "" def testBetween(self): between = verification.Between(1, 2) assert repr(between) == "" mockito-python-1.2.2/tests/verifications_test.py000066400000000000000000000312011372607637100221310ustar00rootroot00000000000000# Copyright (c) 2008-2016 Szczepan Faber, Serhiy Oplakanets, Herr Kaste # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import pytest from .test_base import TestBase from mockito import ( mock, when, verify, forget_invocations, inorder, VerificationError, ArgumentError, verifyNoMoreInteractions, verifyZeroInteractions, verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed, any) from mockito.verification import never class VerificationTestBase(TestBase): def __init__(self, verification_function, *args, **kwargs): self.verification_function = verification_function TestBase.__init__(self, *args, **kwargs) def setUp(self): self.mock = mock() def testVerifies(self): self.mock.foo() self.mock.someOtherMethod(1, "foo", "bar") self.verification_function(self.mock).foo() self.verification_function(self.mock).someOtherMethod(1, "foo", "bar") def testVerifiesWhenMethodIsUsingKeywordArguments(self): self.mock.foo() self.mock.someOtherMethod(1, fooarg="foo", bararg="bar") self.verification_function(self.mock).foo() self.verification_function(self.mock).someOtherMethod(1, bararg="bar", fooarg="foo") def testVerifiesDetectsNamedArguments(self): self.mock.foo(fooarg="foo", bararg="bar") self.verification_function(self.mock).foo(bararg="bar", fooarg="foo") try: self.verification_function(self.mock).foo(bararg="foo", fooarg="bar") self.fail() except VerificationError: pass def testKeywordArgumentsOrderIsUnimportant(self): self.mock.blub( line="blabla", runs="55", failures="1", errors="2") self.verification_function(self.mock).blub( runs="55", failures="1", errors="2", line="blabla") def testFailsVerification(self): self.mock.foo("boo") self.assertRaises(VerificationError, self.verification_function(self.mock).foo, "not boo") def testVerifiesAnyTimes(self): self.mock = mock() self.mock.foo() self.verification_function(self.mock).foo() self.verification_function(self.mock).foo() self.verification_function(self.mock).foo() def testVerifiesMultipleCalls(self): self.mock = mock() self.mock.foo() self.mock.foo() self.mock.foo() self.verification_function(self.mock, times=3).foo() def testVerifiesMultipleCallsWhenMethodUsedAsFunction(self): self.mock = mock() f = self.mock.foo f(1, 2) f('foobar') self.verification_function(self.mock).foo(1, 2) self.verification_function(self.mock).foo('foobar') def testFailsVerificationOfMultipleCalls(self): self.mock = mock() self.mock.foo() self.mock.foo() self.mock.foo() self.assertRaises(VerificationError, self.verification_function(self.mock, times=2).foo) def testVerifiesUsingAnyMatcher(self): self.mock.foo(1, "bar") self.verification_function(self.mock).foo(1, any()) self.verification_function(self.mock).foo(any(), "bar") self.verification_function(self.mock).foo(any(), any()) def testVerifiesUsingAnyIntMatcher(self): self.mock.foo(1, "bar") self.verification_function(self.mock).foo(any(int), "bar") def testFailsVerificationUsingAnyIntMatcher(self): self.mock.foo(1, "bar") self.assertRaises(VerificationError, self.verification_function(self.mock).foo, 1, any(int)) self.assertRaises(VerificationError, self.verification_function(self.mock).foo, any(int)) def testNumberOfTimesDefinedDirectlyInVerify(self): self.mock.foo("bar") self.verification_function(self.mock, times=1).foo("bar") def testFailsWhenTimesIsLessThanZero(self): self.assertRaises(ArgumentError, self.verification_function, None, -1) def testVerifiesAtLeastTwoWhenMethodInvokedTwice(self): self.mock.foo() self.mock.foo() self.verification_function(self.mock, atleast=2).foo() def testVerifiesAtLeastTwoWhenMethodInvokedFourTimes(self): self.mock.foo() self.mock.foo() self.mock.foo() self.mock.foo() self.verification_function(self.mock, atleast=2).foo() def testFailsWhenMethodInvokedOnceForAtLeastTwoVerification(self): self.mock.foo() self.assertRaises(VerificationError, self.verification_function(self.mock, atleast=2).foo) def testVerifiesAtMostTwoWhenMethodInvokedTwice(self): self.mock.foo() self.mock.foo() self.verification_function(self.mock, atmost=2).foo() def testVerifiesAtMostTwoWhenMethodInvokedOnce(self): self.mock.foo() self.verification_function(self.mock, atmost=2).foo() def testFailsWhenMethodInvokedFourTimesForAtMostTwoVerification(self): self.mock.foo() self.mock.foo() self.mock.foo() self.mock.foo() self.assertRaises(VerificationError, self.verification_function(self.mock, atmost=2).foo) def testVerifiesBetween(self): self.mock.foo() self.mock.foo() self.verification_function(self.mock, between=[1, 2]).foo() self.verification_function(self.mock, between=[2, 3]).foo() self.verification_function(self.mock, between=[1, 5]).foo() self.verification_function(self.mock, between=[2, 2]).foo() def testFailsVerificationWithBetween(self): self.mock.foo() self.mock.foo() self.mock.foo() self.assertRaises(VerificationError, self.verification_function(self.mock, between=[1, 2]).foo) self.assertRaises(VerificationError, self.verification_function(self.mock, between=[4, 9]).foo) def testFailsAtMostAtLeastAndBetweenVerificationWithWrongArguments(self): self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=0) self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=-5) self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=0) self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=-5) self.assertRaises(ArgumentError, self.verification_function, self.mock, between=[5, 1]) self.assertRaises(ArgumentError, self.verification_function, self.mock, between=[-1, 1]) self.assertRaises(ArgumentError, self.verification_function, self.mock, between=(0, 1, 2)) self.assertRaises(ArgumentError, self.verification_function, self.mock, between=0) self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, atmost=5) self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, between=[1, 2]) self.assertRaises(ArgumentError, self.verification_function, self.mock, atmost=5, between=[1, 2]) self.assertRaises(ArgumentError, self.verification_function, self.mock, atleast=5, atmost=5, between=[1, 2]) def runTest(self): pass class VerifyTest(VerificationTestBase): def __init__(self, *args, **kwargs): VerificationTestBase.__init__(self, verify, *args, **kwargs) def testVerifyNeverCalled(self): verify(self.mock, never).someMethod() def testVerifyNeverCalledRaisesError(self): self.mock.foo() self.assertRaises(VerificationError, verify(self.mock, never).foo) class InorderVerifyTest(VerificationTestBase): def __init__(self, *args, **kwargs): VerificationTestBase.__init__(self, inorder.verify, *args, **kwargs) def setUp(self): self.mock = mock() def testPassesIfOneIteraction(self): self.mock.first() inorder.verify(self.mock).first() def testPassesIfMultipleInteractions(self): self.mock.first() self.mock.second() self.mock.third() inorder.verify(self.mock).first() inorder.verify(self.mock).second() inorder.verify(self.mock).third() def testFailsIfNoInteractions(self): self.assertRaises(VerificationError, inorder.verify(self.mock).first) def testFailsIfWrongOrderOfInteractions(self): self.mock.first() self.mock.second() self.assertRaises(VerificationError, inorder.verify(self.mock).second) def testErrorMessage(self): self.mock.second() self.mock.first() self.assertRaisesMessage( '\nWanted first() to be invoked,\ngot second() instead.', inorder.verify(self.mock).first) def testPassesMixedVerifications(self): self.mock.first() self.mock.second() verify(self.mock).first() verify(self.mock).second() inorder.verify(self.mock).first() inorder.verify(self.mock).second() def testFailsMixedVerifications(self): self.mock.second() self.mock.first() # first - normal verifications, they should pass verify(self.mock).first() verify(self.mock).second() # but, inorder verification should fail self.assertRaises(VerificationError, inorder.verify(self.mock).first) class VerifyNoMoreInteractionsTest(TestBase): def testVerifies(self): mockOne, mockTwo = mock(), mock() mockOne.foo() mockTwo.bar() verify(mockOne).foo() verify(mockTwo).bar() verifyNoMoreInteractions(mockOne, mockTwo) def testFails(self): theMock = mock() theMock.foo() self.assertRaises(VerificationError, verifyNoMoreInteractions, theMock) class VerifyZeroInteractionsTest(TestBase): def testVerifies(self): theMock = mock() verifyZeroInteractions(theMock) theMock.foo() self.assertRaises( VerificationError, verifyNoMoreInteractions, theMock) class ClearInvocationsTest(TestBase): def testClearsInvocations(self): theMock1 = mock() theMock2 = mock() theMock1.do_foo() theMock2.do_bar() self.assertRaises(VerificationError, verifyZeroInteractions, theMock1) self.assertRaises(VerificationError, verifyZeroInteractions, theMock2) forget_invocations(theMock1, theMock2) verifyZeroInteractions(theMock1) verifyZeroInteractions(theMock2) def testPreservesStubs(self): theMock = mock() when(theMock).do_foo().thenReturn('hello') self.assertEqual('hello', theMock.do_foo()) forget_invocations(theMock) self.assertEqual('hello', theMock.do_foo()) class TestRaiseOnUnknownObjects: @pytest.mark.parametrize('verification_fn', [ verify, verifyNoMoreInteractions, verifyZeroInteractions, verifyNoUnwantedInteractions, verifyStubbedInvocationsAreUsed ]) def testVerifyShouldRaise(self, verification_fn): class Foo(object): pass with pytest.raises(ArgumentError) as exc: verification_fn(Foo) assert str(exc.value) == "obj '%s' is not registered" % Foo mockito-python-1.2.2/tests/when2_test.py000066400000000000000000000073711372607637100203220ustar00rootroot00000000000000 import pytest from mockito import when2, patch, spy2, verify from mockito.utils import newmethod import os pytestmark = pytest.mark.usefixtures("unstub") class Dog(object): def bark(self, sound): return sound def bark_hard(self, sound): return sound + '!' class TestMockito2: def testWhen2(self): rex = Dog() when2(rex.bark, 'Miau').thenReturn('Wuff') when2(rex.bark, 'Miau').thenReturn('Grrr') assert rex.bark('Miau') == 'Grrr' def testPatch(self): rex = Dog() patch(rex.bark, lambda sound: sound + '!') assert rex.bark('Miau') == 'Miau!' def testPatch2(self): rex = Dog() patch(rex.bark, rex.bark_hard) assert rex.bark('Miau') == 'Miau!' def testPatch3(self): rex = Dog() def f(self, sound): return self.bark_hard(sound) f = newmethod(f, rex) patch(rex.bark, f) assert rex.bark('Miau') == 'Miau!' def testAddFnWithPatch(self): rex = Dog() patch(rex, 'newfn', lambda s: s) assert rex.newfn('Hi') == 'Hi' class TestFancyObjResolver: def testWhen2WithArguments(self): # This test is a bit flaky bc pytest does not like a patched # `os.path.exists` module. when2(os.path.commonprefix, '/Foo').thenReturn(False) when2(os.path.commonprefix, '/Foo').thenReturn(True) when2(os.path.exists, '/Foo').thenReturn(True) assert os.path.commonprefix('/Foo') assert os.path.exists('/Foo') def testWhen2WithoutArguments(self): import time when2(time.time).thenReturn('None') assert time.time() == 'None' def testWhenSplitOnNextLine(self): # fmt: off when2( os.path.commonprefix, '/Foo').thenReturn(True) # fmt: on assert os.path.commonprefix('/Foo') def testEnsureWithWhen2SameLine(self): with when2(os.path.commonprefix, '/Foo'): pass def testEnsureWithWhen2SplitLine(self): # fmt: off with when2( os.path.commonprefix, '/Foo'): pass # fmt: on def testEnsureToResolveMethodOnClass(self): class A(object): class B(object): def c(self): pass when2(A.B.c) def testEnsureToResolveClass(self): class A(object): class B(object): pass when2(A.B, 'Hi').thenReturn('Ho') assert A.B('Hi') == 'Ho' def testPatch(self): patch(os.path.commonprefix, lambda m: 'yup') patch(os.path.commonprefix, lambda m: 'yep') assert os.path.commonprefix(Ellipsis) == 'yep' def testWithPatchGivenTwoArgs(self): with patch(os.path.exists, lambda m: 'yup'): assert os.path.exists('foo') == 'yup' assert not os.path.exists('foo') def testWithPatchGivenThreeArgs(self): with patch(os.path, 'exists', lambda m: 'yup'): assert os.path.exists('foo') == 'yup' assert not os.path.exists('foo') def testSpy2(self): spy2(os.path.exists) assert os.path.exists('/Foo') is False verify(os.path).exists('/Foo') class TestRejections: def testA(self): with pytest.raises(TypeError) as exc: when2(os) assert str(exc.value) == "can't guess origin of 'os'" cp = os.path.commonprefix with pytest.raises(TypeError) as exc: spy2(cp) assert str(exc.value) == "can't guess origin of 'cp'" ptch = patch with pytest.raises(TypeError) as exc: ptch(os.path.exists, lambda: 'boo') assert str(exc.value) == "could not destructure first argument" mockito-python-1.2.2/tests/when_interface_test.py000066400000000000000000000067631372607637100222640ustar00rootroot00000000000000 import pytest from mockito import when, when2, expect, verify, patch, mock, spy2 from mockito.invocation import InvocationError class Dog(object): def bark(self): pass class Unhashable(object): def update(self, **kwargs): pass def __hash__(self): raise TypeError("I'm immutable") @pytest.mark.usefixtures('unstub') class TestUserExposedInterfaces: def testWhen(self): whening = when(Dog) assert whening.__dict__ == {} def testExpect(self): expecting = expect(Dog) assert expecting.__dict__ == {} def testVerify(self): dummy = mock() verifying = verify(dummy) assert verifying.__dict__ == {} def testEnsureUnhashableObjectCanBeMocked(self): obj = Unhashable() when(obj).update().thenReturn(None) @pytest.mark.usefixtures('unstub') class TestPassAroundStrictness: def testReconfigureStrictMock(self): when(Dog).bark() # important first call, inits theMock when(Dog, strict=False).waggle().thenReturn('Sure') expect(Dog, strict=False).weggle().thenReturn('Sure') with pytest.raises(InvocationError): when(Dog).wuggle() with pytest.raises(InvocationError): when(Dog).woggle() rex = Dog() assert rex.waggle() == 'Sure' assert rex.weggle() == 'Sure' # For documentation; the inital strict value of the mock will be used # here. So the above when(..., strict=False) just assures we can # actually *add* an attribute to the mocked object with pytest.raises(InvocationError): rex.waggle(1) verify(Dog).waggle() verify(Dog).weggle() def testReconfigureLooseMock(self): when(Dog, strict=False).bark() # important first call, inits theMock when(Dog, strict=False).waggle().thenReturn('Sure') expect(Dog, strict=False).weggle().thenReturn('Sure') with pytest.raises(InvocationError): when(Dog).wuggle() with pytest.raises(InvocationError): when(Dog).woggle() rex = Dog() assert rex.waggle() == 'Sure' assert rex.weggle() == 'Sure' # For documentation; see test above. strict is inherited from the # initial mock. So we return `None` assert rex.waggle(1) is None verify(Dog).waggle() verify(Dog).weggle() # Where to put this test? def testEnsureAddedAttributesGetRemovedOnUnstub(self): with when(Dog, strict=False).wggle(): pass with pytest.raises(AttributeError): getattr(Dog, 'wggle') @pytest.mark.usefixtures('unstub') class TestDottedPaths: def testWhen(self): when('os.path').exists('/Foo').thenReturn(True) import os.path assert os.path.exists('/Foo') def testWhen2(self): when2('os.path.exists', '/Foo').thenReturn(True) import os.path assert os.path.exists('/Foo') def testPatch(self): dummy = mock() patch('os.path.exists', dummy) import os.path assert os.path.exists('/Foo') is None verify(dummy).__call__('/Foo') def testVerify(self): when('os.path').exists('/Foo').thenReturn(True) import os.path os.path.exists('/Foo') verify('os.path', times=1).exists('/Foo') def testSpy2(self): spy2('os.path.exists') import os.path assert not os.path.exists('/Foo') verify('os.path', times=1).exists('/Foo')