├── .gitignore ├── CHANGELOG ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── Makefile ├── api.rst ├── compare.rst ├── conf.py ├── index.rst ├── start.rst └── user-guide.rst ├── flexmock.py ├── setup.py └── tests ├── flexmock_modern_test.py ├── flexmock_nose_test.py ├── flexmock_pytest_test.py ├── flexmock_test.py ├── flexmock_unittest_test.py ├── py3_only_features.py └── run_tests.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | docs/_build 3 | build/ 4 | dist/ 5 | *.egg-info 6 | *.pyc 7 | *.swp 8 | tags 9 | MANIFEST 10 | .project 11 | .ropeproject 12 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Release 0.9.7 2 | - small update to add support for TeamCity / PyCharm test runner. 3 | 4 | Release 0.9.6 5 | - fix staticmethod mocking on instances 6 | - fix comparison of kwargs ordering issues 7 | - fix ReturnValue.__str__ 8 | 9 | Release 0.9.5 10 | - bugfix: stop enforcing argument signatures on flexmock objects 11 | 12 | Release 0.9.4 13 | - add support for stubbing return values on getter properties 14 | - add custom matcher object support to with_args 15 | - add support for striter function signature checks 16 | - add support for non-callable attributes 17 | - add support chained attributes (thanks Bryce Covert!) 18 | - add iter support to Mock objects 19 | - add PyPy support 20 | - add Jython support 21 | - fix should_call to work with class mocks 22 | - fix and_return to return None by default 23 | - fix MRO issues on builtin methods on 2.7+/3.2+ 24 | - imporove defaults: partial mocks created using the func=return_value 25 | style now default to replace_with instead of should_receive for callables 26 | 27 | Release 0.9.3 28 | - add python 3.3 test target 29 | - add proper handling of ordered() expectation across different methods 30 | - add property support on fake objects 31 | - fix compatibility with pytest 2.2 (thanks jpvanhal!) 32 | - fix insidious bug with mocking subclasses of str class 33 | - fix tuple handling when formatting arguments 34 | - fix reseting subclass methods 35 | 36 | Release 0.9.2 37 | - fix mocking builtins by reseting expectation when raising exceptions 38 | - fix mocking private methods on classes with leading underscores 39 | - limit the damage of "from flexmock import *" by limiting to just flexmock() 40 | - ensure _pre_flexmock_success is cleaned up after each test 41 | 42 | Release 0.9.1 43 | - adding support for more test runners: 44 | * unittest2 45 | * django 46 | * twisted/trial 47 | * zope.testrunner 48 | * subunit 49 | * testtools 50 | 51 | Release 0.9.0 52 | - adding state machine support using when() 53 | - make expectation fail as soon as number of expected calls is exceeded 54 | - flexmock_teardown no longer returns a function 55 | - allow should_call on class and static methods 56 | - disallow should_call on class mocks 57 | - fixing unicode args handling 58 | - fixing issues with @property methods misbehaving in the debugger 59 | - fixing pytest integration and instance teardown 60 | - fixing private method handling 61 | 62 | Release 0.8.1 63 | - fixing pytest and doctest integration to always call flexmock_teardown 64 | - fixing flexmock_teardown to return a function as before so it can be used as a decorator 65 | 66 | Release 0.8.0 67 | - big changes in runner integration support (no more stack examination or sketchy teardown replacement) 68 | - doctest integration 69 | - fixing ordering verification when the method has a default stub 70 | - fixing calling with_args() without arguments to match exactly no arguments (thanks jerico-dev!) 71 | - 20% performance improvement 72 | - make sure to return object itself when partial mocking instances unless the object already has some of the methods 73 | - ensure consecutive calls return same mock object 74 | 75 | Release 0.7.4.2 76 | - adding regex support for arg matching and spy return values 77 | - enabling replace_with for class mocks 78 | - disabling expectation checking if an exception has already been raised 79 | - massive refactoring of the way flexmock does monkey patching 80 | 81 | Release 0.7.4.1 82 | - Fixing replace_with to work properly like and_execute 83 | - (and_execute will be deprecated in next release!) 84 | 85 | Release 0.7.4 86 | - Fixed exception type check when no message specified 87 | - Make properties work optionally with parentheses 88 | - Make sure should_receive does not replace flexmock methods 89 | - Removed new_instances= param in favor of new_instances() method 90 | - Refactoring to move all state to FlexmockContainer class 91 | 92 | Release 0.7.3 93 | - Added new_instances method (new_instances param will be deprecated in next release!) 94 | - Added replace_with to enable returning results of custom functions 95 | - Added "with" support for FlexMock objects 96 | - Moved tests to their own directory 97 | - Lots of documentation cleanup and updates 98 | 99 | Release 0.7.2 100 | - Added support for chained methods 101 | - Moved flexmock_teardown to module level to expose it for other test runners 102 | - Added py.test support (thanks to derdon) 103 | - Lots of test refactoring and improvements for multiple test runner support 104 | - Fix loop in teardown 105 | - Fix should_call for same method with different args 106 | 107 | Release 0.7.1 108 | - Fix bug with "never" not working when the expectation is not met 109 | - Fix bug in duplicate calls to original method in pass_thru mode (thanks sagara-!) 110 | - Fix bug in handling unicode characters in ReturnValue 111 | 112 | Release 0.7.0 113 | - Better error handling for trying to mock builtins 114 | - Added simple test harness for running on multiple versions / test runners 115 | - Fixed unicode arg formatting (thanks to sagara-!) 116 | - Made it impossible to mock non-existent methods 117 | - Ensure flexmock teardown takes varargs (for better runner integration) 118 | 119 | Release 0.6.9 120 | - Initial nose integration (still no support for generated tests) 121 | - Fixing private class methods 122 | - Some test refactoring to support different test runners 123 | 124 | Release 0.6.8 125 | - Add should_call() alias for should_receive().and_execute 126 | - Ensure new_instances can't be used with expectation modifiers 127 | - Make and_execute match return value by class in addition to value 128 | - Support for mocking out static methods 129 | - Bit of test fixage (thanks to derdon) 130 | 131 | Release 0.6.7 132 | - Fixing clobbering of original method by multiple flexmock calls 133 | - Making and_raise work properly with exception classes and args 134 | - Proper exception matching with and_execute 135 | - Fix mocking same class twice 136 | 137 | Release 0.6.6 138 | - Removing extra args from should_receive 139 | - Making and_execute check return/raise value of original method 140 | - Refactoring FlexMock constructor into factory method 141 | - Fixing new_instances to accept multiple args instead of just none 142 | - Raising an exception when and_execute is set on class mock 143 | 144 | Release 0.6.5 145 | - Adding support for multiple flexmock() calls on same object 146 | - Adding error detection on and_execute for missing or unbound methods 147 | - Make sure empty args don't include None 148 | 149 | Release 0.6.4 150 | - Fixing up teardown cleanup code after an exception is raised in tests 151 | - Fixing and_yield to return proper generator 152 | - Adding and_yield returning a predefined generator 153 | - Replacing and_passthru with and_execute 154 | - Make it easier to mock private methods 155 | 156 | Release 0.6.3 157 | - Adding keyword argument expectation matching 158 | 159 | Release 0.6.2 160 | - Changing and_return(multiple=True) to one_by_one 161 | - Making it possible to supply multiple args to and_return instead of a tuple 162 | - Changing default mock behavior to create attributes instead of methods 163 | - FIX teardown for python3 164 | 165 | Release 0.6.1 166 | - Make it even easier to integrate with new test runners 167 | - Adding support for mixing returns and raises in return values 168 | 169 | Release 0.6 170 | - Adding support for multiple arg type matches 171 | - Pulling out the entry point code from constructor into its own method. 172 | 173 | Release 0.5 174 | - FIX: ensuring that mocks are cleaned up properly between tests 175 | - BROKEN: part1 on ensuring mocking multiple objects works correctly 176 | - Make sure pass_thru doesn't try to call a non-existent method 177 | - Fixing up copyright notice 178 | - Adding some missing pydocs 179 | 180 | Release 0.4 181 | - Fixing tests and ensuring mock methods really get created properly 182 | - Making sure shortcuts create methods rather than attributes 183 | - Fixing doc strings 184 | - Removing the new-style/old-style convert code, it's stupid 185 | 186 | Release 0.3 187 | - Making Expectation.mock into a property so that it shows up in pydoc 188 | - Adding proxying/spying and at_least/at_most expectation modifiers 189 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2015 Herman Sheremetyev, Slavek Kabrda. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.py 2 | include CHANGELOG 3 | include LICENSE 4 | include README.md 5 | recursive-include tests *py *sh 6 | include docs/conf.py 7 | include docs/Makefile 8 | recursive-include docs *.rst 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ATTENTION: this project is now hosted at https://github.com/bkabrda/flexmock 2 | 3 | Send any pull requests and file new bug reports there. 4 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(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/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/flexmock.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/flexmock.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/flexmock" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/flexmock" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | flexmock API 2 | ============ 3 | 4 | .. module:: flexmock 5 | 6 | .. autofunction:: flexmock 7 | 8 | .. autoclass:: Mock 9 | :members: should_receive, should_call, new_instances 10 | 11 | .. autoclass:: Expectation 12 | :members: with_args, and_return, and_raise, replace_with, and_yield, when, times, at_least, at_most, ordered, one_by_one, mock 13 | -------------------------------------------------------------------------------- /docs/compare.rst: -------------------------------------------------------------------------------- 1 | Mock Library Comparison 2 | ======================= 3 | 4 | (flexmock for Mox or Mock users.) 5 | --------------------------------------------------------------- 6 | 7 | This document shows a side-by-side comparison of how to accomplish some 8 | basic tasks with flexmock as well as other popular Python mocking libraries. 9 | 10 | Simple fake object (attributes only) 11 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 | 13 | :: 14 | 15 | # flexmock 16 | mock = flexmock(some_attribute="value", some_other_attribute="value2") 17 | assertEquals("value", mock.some_attribute) 18 | assertEquals("value2", mock.some_other_attribute) 19 | 20 | # Mox 21 | mock = mox.MockAnything() 22 | mock.some_attribute = "value" 23 | mock.some_other_attribute = "value2" 24 | assertEquals("value", mock.some_attribute) 25 | assertEquals("value2", mock.some_other_attribute) 26 | 27 | # Mock 28 | my_mock = mock.Mock() 29 | my_mock.some_attribute = "value" 30 | my_mock.some_other_attribute = "value2" 31 | assertEquals("value", my_mock.some_attribute) 32 | assertEquals("value2", my_mock.some_other_attribute) 33 | 34 | 35 | Simple fake object (with methods) 36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | :: 39 | 40 | # flexmock 41 | mock = flexmock(some_method=lambda: "calculated value") 42 | assertEquals("calculated value", mock.some_method()) 43 | 44 | # Mox 45 | mock = mox.MockAnything() 46 | mock.some_method().AndReturn("calculated value") 47 | mox.Replay(mock) 48 | assertEquals("calculated value", mock.some_method()) 49 | 50 | # Mock 51 | my_mock = mock.Mock() 52 | my_mock.some_method.return_value = "calculated value" 53 | assertEquals("calculated value", my_mock.some_method()) 54 | 55 | 56 | Simple mock 57 | ~~~~~~~~~~~ 58 | 59 | :: 60 | 61 | # flexmock 62 | mock = flexmock() 63 | mock.should_receive("some_method").and_return("value").once() 64 | assertEquals("value", mock.some_method()) 65 | 66 | # Mox 67 | mock = mox.MockAnything() 68 | mock.some_method().AndReturn("value") 69 | mox.Replay(mock) 70 | assertEquals("value", mock.some_method()) 71 | mox.Verify(mock) 72 | 73 | # Mock 74 | my_mock = mock.Mock() 75 | my_mock.some_method.return_value = "value" 76 | assertEquals("value", mock.some_method()) 77 | my_mock.some_method.assert_called_once_with() 78 | 79 | 80 | Creating partial mocks 81 | ~~~~~~~~~~~~~~~~~~~~~~ 82 | 83 | :: 84 | 85 | # flexmock 86 | flexmock(SomeObject).should_receive("some_method").and_return('value') 87 | assertEquals("value", mock.some_method()) 88 | 89 | # Mox 90 | mock = mox.MockObject(SomeObject) 91 | mock.some_method().AndReturn("value") 92 | mox.Replay(mock) 93 | assertEquals("value", mock.some_method()) 94 | mox.Verify(mock) 95 | 96 | # Mock 97 | with mock.patch("SomeObject") as my_mock: 98 | my_mock.some_method.return_value = "value" 99 | assertEquals("value", mock.some_method()) 100 | 101 | 102 | Ensure calls are made in specific order 103 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 | 105 | :: 106 | 107 | # flexmock 108 | mock = flexmock(SomeObject) 109 | mock.should_receive('method1').once().ordered().and_return('first thing') 110 | mock.should_receive('method2').once().ordered().and_return('second thing') 111 | # exercise the code 112 | 113 | # Mox 114 | mock = mox.MockObject(SomeObject) 115 | mock.method1().AndReturn('first thing') 116 | mock.method2().AndReturn('second thing') 117 | mox.Replay(mock) 118 | # exercise the code 119 | mox.Verify(mock) 120 | 121 | # Mock 122 | mock = mock.Mock(spec=SomeObject) 123 | mock.method1.return_value = 'first thing' 124 | mock.method2.return_value = 'second thing' 125 | # exercise the code 126 | assert mock.method_calls == [('method1',) ('method2',)] 127 | 128 | 129 | Raising exceptions 130 | ~~~~~~~~~~~~~~~~~~ 131 | 132 | :: 133 | 134 | # flexmock 135 | mock = flexmock() 136 | mock.should_receive("some_method").and_raise(SomeException("message")) 137 | assertRaises(SomeException, mock.some_method) 138 | 139 | # Mox 140 | mock = mox.MockAnything() 141 | mock.some_method().AndRaise(SomeException("message")) 142 | mox.Replay(mock) 143 | assertRaises(SomeException, mock.some_method) 144 | mox.Verify(mock) 145 | 146 | # Mock 147 | my_mock = mock.Mock() 148 | my_mock.some_method.side_effect = SomeException("message") 149 | assertRaises(SomeException, my_mock.some_method) 150 | 151 | 152 | Override new instances of a class 153 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 154 | 155 | :: 156 | 157 | # flexmock 158 | flexmock(some_module.SomeClass).new_instances(some_other_object) 159 | assertEqual(some_other_object, some_module.SomeClass()) 160 | 161 | # Mox 162 | # (you will probably have mox.Mox() available as self.mox in a real test) 163 | mox.Mox().StubOutWithMock(some_module, 'SomeClass', use_mock_anything=True) 164 | some_module.SomeClass().AndReturn(some_other_object) 165 | mox.ReplayAll() 166 | assertEqual(some_other_object, some_module.SomeClass()) 167 | 168 | # Mock 169 | with mock.patch('somemodule.Someclass') as MockClass: 170 | MockClass.return_value = some_other_object 171 | assert some_other_object == some_module.SomeClass() 172 | 173 | 174 | Verify a method was called multiple times 175 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 176 | 177 | :: 178 | 179 | # flexmock (verifies that the method gets called at least twice) 180 | flexmock(some_object).should_receive('some_method').at_least().twice() 181 | # exercise the code 182 | 183 | # Mox 184 | # (does not support variable number of calls, so you need to create a new entry for each explicit call) 185 | mock = mox.MockObject(some_object) 186 | mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) 187 | mock.some_method(mox.IgnoreArg(), mox.IgnoreArg()) 188 | mox.Replay(mock) 189 | # exercise the code 190 | mox.Verify(mock) 191 | 192 | # Mock 193 | my_mock = mock.Mock(spec=SomeObject) 194 | # exercise the code 195 | assert my_mock.some_method.call_count >= 2 196 | 197 | 198 | Mock chained methods 199 | ~~~~~~~~~~~~~~~~~~~~ 200 | 201 | :: 202 | 203 | # flexmock 204 | # (intermediate method calls are automatically assigned to temporary fake objects 205 | # and can be called with any arguments) 206 | (flexmock(some_object) 207 | .should_receive('method1.method2.method3') 208 | .with_args(arg1, arg2) 209 | .and_return('some value')) 210 | assertEqual('some_value', some_object.method1().method2().method3(arg1, arg2)) 211 | 212 | # Mox 213 | mock = mox.MockObject(some_object) 214 | mock2 = mox.MockAnything() 215 | mock3 = mox.MockAnything() 216 | mock.method1().AndReturn(mock1) 217 | mock2.method2().AndReturn(mock2) 218 | mock3.method3(arg1, arg2).AndReturn('some_value') 219 | self.mox.ReplayAll() 220 | assertEqual("some_value", some_object.method1().method2().method3(arg1, arg2)) 221 | self.mox.VerifyAll() 222 | 223 | # Mock 224 | my_mock = mock.Mock() 225 | my_mock.method1.return_value.method2.return_value.method3.return_value = 'some value' 226 | method3 = my_mock.method1.return_value.method2.return_value.method3 227 | method3.assert_called_once_with(arg1, arg2) 228 | assertEqual('some_value', my_mock.method1().method2().method3(arg1, arg2)) 229 | 230 | 231 | Mock context manager 232 | ~~~~~~~~~~~~~~~~~~~~ 233 | 234 | :: 235 | 236 | # flexmock 237 | my_mock = flexmock() 238 | with my_mock: 239 | pass 240 | 241 | # Mock 242 | my_mock = mock.MagicMock() 243 | with my_mock: 244 | pass 245 | 246 | # Mox 247 | my_mock = mox.MockAnything() 248 | with my_mock: 249 | pass 250 | 251 | 252 | Mocking the builtin open used as a context manager 253 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 254 | 255 | The following examples work in an interactive Python session but may not work 256 | quite the same way in a script, or with Python 3.0+. See examples in the 257 | :ref:`builtin_functions` section for more specific flexmock instructions 258 | on mocking builtins. 259 | 260 | :: 261 | 262 | # flexmock 263 | (flexmock(__builtins__) 264 | .should_receive('open') 265 | .once() 266 | .with_args('file_name') 267 | .and_return(flexmock(read=lambda: 'some data'))) 268 | with open('file_name') as f: 269 | assertEqual('some data', f.read()) 270 | 271 | # Mox 272 | self_mox = mox.Mox() 273 | mock_file = mox.MockAnything() 274 | mock_file.read().AndReturn('some data') 275 | self_mox.StubOutWithMock(__builtins__, 'open') 276 | __builtins__.open('file_name').AndReturn(mock_file) 277 | self_mox.ReplayAll() 278 | with mock_file: 279 | assertEqual('some data', mock_file.read()) 280 | self_mox.VerifyAll() 281 | 282 | # Mock 283 | with mock.patch('__builtin__.open') as my_mock: 284 | my_mock.return_value.__enter__ = lambda s: s 285 | my_mock.return_value.__exit__ = mock.Mock() 286 | my_mock.return_value.read.return_value = 'some data' 287 | with open('file_name') as h: 288 | assertEqual('some data', h.read()) 289 | my_mock.assert_called_once_with('foo') 290 | 291 | 292 | A possibly more up-to-date version of this document, featuring more mocking 293 | libraries, is availale at: 294 | 295 | http://garybernhardt.github.com/python-mock-comparison/ 296 | 297 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # flexmock documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Dec 2 18:58:20 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | 18 | # If extensions (or modules to document with autodoc) are in another directory, 19 | # add these directories to sys.path here. If the directory is relative to the 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. 21 | #sys.path.insert(0, os.path.abspath('.')) 22 | 23 | # -- General configuration ------------------------------------------------ 24 | 25 | # If your documentation needs a minimal Sphinx version, state it here. 26 | #needs_sphinx = '1.0' 27 | 28 | # Add any Sphinx extension module names here, as strings. They can be 29 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 30 | # ones. 31 | extensions = ['sphinx.ext.viewcode', 'sphinx.ext.autodoc'] 32 | 33 | # Add any paths that contain templates here, relative to this directory. 34 | templates_path = ['_templates'] 35 | 36 | # The suffix of source filenames. 37 | source_suffix = '.rst' 38 | 39 | # The encoding of source files. 40 | #source_encoding = 'utf-8-sig' 41 | 42 | # The master toctree document. 43 | master_doc = 'index' 44 | 45 | # General information about the project. 46 | project = u'flexmock' 47 | copyright = u'2015, Slavek Kabrda, Herman Sheremetyev' 48 | 49 | # The version info for the project you're documenting, acts as replacement for 50 | # |version| and |release|, also used in various other places throughout the 51 | # built documents. 52 | # 53 | # The short X.Y version. 54 | version = '0.9.7' 55 | # The full version, including alpha/beta/rc tags. 56 | release = '0.9.7' 57 | 58 | # The language for content autogenerated by Sphinx. Refer to documentation 59 | # for a list of supported languages. 60 | #language = None 61 | 62 | # There are two options for replacing |today|: either, you set today to some 63 | # non-false value, then it is used: 64 | #today = '' 65 | # Else, today_fmt is used as the format for a strftime call. 66 | #today_fmt = '%B %d, %Y' 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | exclude_patterns = ['_build'] 71 | 72 | # The reST default role (used for this markup: `text`) to use for all 73 | # documents. 74 | #default_role = None 75 | 76 | # If true, '()' will be appended to :func: etc. cross-reference text. 77 | #add_function_parentheses = True 78 | 79 | # If true, the current module name will be prepended to all description 80 | # unit titles (such as .. function::). 81 | #add_module_names = True 82 | 83 | # If true, sectionauthor and moduleauthor directives will be shown in the 84 | # output. They are ignored by default. 85 | #show_authors = False 86 | 87 | # The name of the Pygments (syntax highlighting) style to use. 88 | pygments_style = 'sphinx' 89 | 90 | # A list of ignored prefixes for module index sorting. 91 | #modindex_common_prefix = [] 92 | 93 | # If true, keep warnings as "system message" paragraphs in the built documents. 94 | #keep_warnings = False 95 | 96 | 97 | # -- Options for HTML output ---------------------------------------------- 98 | 99 | # The theme to use for HTML and HTML Help pages. See the documentation for 100 | # a list of builtin themes. 101 | html_theme = 'default' 102 | 103 | # Theme options are theme-specific and customize the look and feel of a theme 104 | # further. For a list of options available for each theme, see the 105 | # documentation. 106 | #html_theme_options = {} 107 | 108 | # Add any paths that contain custom themes here, relative to this directory. 109 | #html_theme_path = [] 110 | 111 | # The name for this set of Sphinx documents. If None, it defaults to 112 | # " v documentation". 113 | #html_title = None 114 | 115 | # A shorter title for the navigation bar. Default is the same as html_title. 116 | #html_short_title = None 117 | 118 | # The name of an image file (relative to this directory) to place at the top 119 | # of the sidebar. 120 | #html_logo = None 121 | 122 | # The name of an image file (within the static path) to use as favicon of the 123 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 124 | # pixels large. 125 | #html_favicon = None 126 | 127 | # Add any paths that contain custom static files (such as style sheets) here, 128 | # relative to this directory. They are copied after the builtin static files, 129 | # so a file named "default.css" will overwrite the builtin "default.css". 130 | html_static_path = ['_static'] 131 | 132 | # Add any extra paths that contain custom files (such as robots.txt or 133 | # .htaccess) here, relative to this directory. These files are copied 134 | # directly to the root of the documentation. 135 | #html_extra_path = [] 136 | 137 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 138 | # using the given strftime format. 139 | #html_last_updated_fmt = '%b %d, %Y' 140 | 141 | # If true, SmartyPants will be used to convert quotes and dashes to 142 | # typographically correct entities. 143 | #html_use_smartypants = True 144 | 145 | # Custom sidebar templates, maps document names to template names. 146 | #html_sidebars = {} 147 | 148 | # Additional templates that should be rendered to pages, maps page names to 149 | # template names. 150 | #html_additional_pages = {} 151 | 152 | # If false, no module index is generated. 153 | #html_domain_indices = True 154 | 155 | # If false, no index is generated. 156 | #html_use_index = True 157 | 158 | # If true, the index is split into individual pages for each letter. 159 | #html_split_index = False 160 | 161 | # If true, links to the reST sources are added to the pages. 162 | #html_show_sourcelink = True 163 | 164 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 165 | #html_show_sphinx = True 166 | 167 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 168 | #html_show_copyright = True 169 | 170 | # If true, an OpenSearch description file will be output, and all pages will 171 | # contain a tag referring to it. The value of this option must be the 172 | # base URL from which the finished HTML is served. 173 | #html_use_opensearch = '' 174 | 175 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 176 | #html_file_suffix = None 177 | 178 | # Output file base name for HTML help builder. 179 | htmlhelp_basename = 'flexmockdoc' 180 | 181 | 182 | # -- Options for LaTeX output --------------------------------------------- 183 | 184 | latex_elements = { 185 | # The paper size ('letterpaper' or 'a4paper'). 186 | #'papersize': 'letterpaper', 187 | 188 | # The font size ('10pt', '11pt' or '12pt'). 189 | #'pointsize': '10pt', 190 | 191 | # Additional stuff for the LaTeX preamble. 192 | #'preamble': '', 193 | } 194 | 195 | # Grouping the document tree into LaTeX files. List of tuples 196 | # (source start file, target name, title, 197 | # author, documentclass [howto, manual, or own class]). 198 | latex_documents = [ 199 | ('index', 'flexmock.tex', u'flexmock Documentation', 200 | u'Slavek Kabrda, Herman Sheremetyev', 'manual'), 201 | ] 202 | 203 | # The name of an image file (relative to this directory) to place at the top of 204 | # the title page. 205 | #latex_logo = None 206 | 207 | # For "manual" documents, if this is true, then toplevel headings are parts, 208 | # not chapters. 209 | #latex_use_parts = False 210 | 211 | # If true, show page references after internal links. 212 | #latex_show_pagerefs = False 213 | 214 | # If true, show URL addresses after external links. 215 | #latex_show_urls = False 216 | 217 | # Documents to append as an appendix to all manuals. 218 | #latex_appendices = [] 219 | 220 | # If false, no module index is generated. 221 | #latex_domain_indices = True 222 | 223 | 224 | # -- Options for manual page output --------------------------------------- 225 | 226 | # One entry per manual page. List of tuples 227 | # (source start file, name, description, authors, manual section). 228 | man_pages = [ 229 | ('index', 'flexmock', u'flexmock Documentation', 230 | [u'Slavek Kabrda, Herman Sheremetyev'], 1) 231 | ] 232 | 233 | # If true, show URL addresses after external links. 234 | #man_show_urls = False 235 | 236 | 237 | # -- Options for Texinfo output ------------------------------------------- 238 | 239 | # Grouping the document tree into Texinfo files. List of tuples 240 | # (source start file, target name, title, author, 241 | # dir menu entry, description, category) 242 | texinfo_documents = [ 243 | ('index', 'flexmock', u'flexmock Documentation', 244 | u'Slavek Kabrda, Herman Sheremetyev', 'flexmock', 'One line description of project.', 245 | 'Miscellaneous'), 246 | ] 247 | 248 | # Documents to append as an appendix to all manuals. 249 | #texinfo_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | #texinfo_domain_indices = True 253 | 254 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 255 | #texinfo_show_urls = 'footnote' 256 | 257 | # If true, do not generate a @detailmenu in the "Top" node's menu. 258 | #texinfo_no_detailmenu = False 259 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ==================================== 2 | flexmock - Testing Library 3 | ==================================== 4 | 5 | :Authors: `Slavek Kabrda `_, `Herman Sheremetyev `_ 6 | :Version: |version| 7 | :Homepage: `flexmock Homepage`_ 8 | :Contribute: `flexmock on Github`_ 9 | :Download: `http://pypi.python.org/pypi/flexmock `_ 10 | :License: `FreeBSD-style License`_ 11 | :Issue tracker: `Issue Tracker `_ 12 | :Twitter: `Follow pyflexmock `_ 13 | 14 | .. _flexmock on Github: http://github.com/has207/flexmock 15 | .. _flexmock Homepage: http://flexmock.readthedocs.org 16 | .. _FreeBSD-style License: http://github.com/has207/flexmock/blob/master/LICENSE 17 | 18 | flexmock is a testing library for Python. 19 | 20 | Its API is inspired by a Ruby library of the same name. 21 | However, it is not a goal of Python flexmock to be a clone of the Ruby version. 22 | Instead, the focus is on providing full support for testing Python programs 23 | and making the creation of fake objects as unobtrusive as possible. 24 | 25 | As a result, Python flexmock removes a number of redundancies in 26 | the Ruby flexmock API, alters some defaults, and introduces a number of Python-only features. 27 | 28 | flexmock's design focuses on simplicity and intuitivenes. This means that the API 29 | is as lean as possible, though a few convenient short-hand methods are provided to aid 30 | brevity and readability. 31 | 32 | flexmock declarations are structured to read more like English sentences than API calls, 33 | and it is possible to chain them together in any order to achieve high degree of 34 | expressiveness in a single line of code. 35 | 36 | Installation 37 | ============ 38 | 39 | :: 40 | 41 | $ sudo easy_install flexmock 42 | 43 | Or download the tarball, unpack it and run: 44 | 45 | :: 46 | 47 | $ sudo python setup.py install 48 | 49 | 50 | Compatibility 51 | ============= 52 | 53 | Tested to work with: 54 | 55 | - python 2.6 56 | - python 2.7 57 | - python 3.3 58 | - python 3.4 59 | - python 3.5 60 | - pypy 61 | - pypy3 62 | - jython 63 | 64 | Automatically integrates with all major test runners, including: 65 | 66 | - unittest 67 | - unittest2 68 | - nose 69 | - py.test 70 | - django 71 | - twisted / trial 72 | - doctest 73 | - zope.testrunner 74 | - subunit 75 | - testtools 76 | 77 | Start Here 78 | ========== 79 | 80 | .. toctree:: 81 | 82 | start 83 | 84 | User Guide 85 | =================== 86 | 87 | .. toctree:: 88 | 89 | user-guide 90 | 91 | API 92 | === 93 | 94 | .. toctree:: 95 | 96 | api 97 | 98 | Comparison 99 | ========== 100 | 101 | .. toctree:: 102 | 103 | compare 104 | -------------------------------------------------------------------------------- /docs/start.rst: -------------------------------------------------------------------------------- 1 | Start Here 2 | ========== 3 | 4 | 5 | So what does flexmock actually help you do? 6 | 7 | 8 | Creating fake objects 9 | --------------------- 10 | 11 | 12 | Making a new object in Python requires defining a new class with all the 13 | fake methods and attributes you're interested in emulating and then instantiating it. 14 | For example, to create a FakePlane object to use in a test in place of a real Plane object we would need to do something like: 15 | 16 | :: 17 | 18 | class FakePlane(object): 19 | operational = True 20 | model = "MIG-21" 21 | def fly(self): pass 22 | 23 | plane = FakePlane() # this is tedious! 24 | 25 | In other words, we must first create a class, make sure it contains all required attributes and methods, and finally instantiate it to create the object. 26 | 27 | flexmock provides an easier way to generate a fake object on the fly using the flexmock() 28 | function: 29 | 30 | :: 31 | 32 | plane = flexmock( 33 | operational=True, 34 | model="MIG-21") 35 | 36 | 37 | It is also possible to add methods to this object using the same notation and Python's handy lambda keyword to turn an attribute into a method: 38 | 39 | :: 40 | 41 | plane = flexmock( 42 | operational=True, 43 | model="MIG-21", 44 | fly=lambda: None) 45 | 46 | 47 | Replacing parts of existing objects and classes (stubs) 48 | ------------------------------------------------------- 49 | 50 | 51 | While creating fake objects from scratch is often sufficient, many times it is easier 52 | to take an existing object and simply stub out certain methods or replace them with 53 | fake ones. flexmock makes this easy as well: 54 | 55 | :: 56 | 57 | flexmock( 58 | Train, # this can be an instance, a class, or a module 59 | get_destination="Tokyo", 60 | get_speed=200) 61 | 62 | 63 | By passing a real object (or class or module) into the flexmock() function as the first argument 64 | it is possible to modify that object in place and provide default return values for 65 | any of its existing methods. 66 | 67 | In addition to simply stubbing out return values, it can be useful to be able to call 68 | an entirely different method and substitute return values based on test-specific conditions: 69 | 70 | :: 71 | 72 | (flexmock(Train) 73 | .should_receive("get_route") 74 | .replace_with(lambda x: custom_get_route())) 75 | 76 | 77 | Creating and checking expectations 78 | ---------------------------------- 79 | 80 | flexmock features smooth integration with pretty much every popular test runner, so no special setup is necessary. Simply 81 | importing flexmock into your test module is sufficient to get started with any of the 82 | following examples. 83 | 84 | 85 | Mocks 86 | ~~~~~ 87 | 88 | 89 | Expectations take many flavors, and flexmock has many different facilities and modes to generate them. 90 | The first and simplest is ensuring that a certain method is called: 91 | 92 | :: 93 | 94 | flexmock(Train).should_receive("get_destination").once() 95 | 96 | 97 | The .once() modifier ensures that Train.get_destination() is called at some point during the test and 98 | will raise an exception if this does not happen. 99 | 100 | Of course, it is also possible to provide a default return value: 101 | 102 | :: 103 | 104 | flexmock(Train).should_receive("get_destination").once().and_return("Tokyo") 105 | 106 | 107 | Or check that a method is called with specific arguments: 108 | 109 | :: 110 | 111 | flexmock(Train).should_receive("set_destination").with_args("Tokyo").at_least().times(1) 112 | 113 | 114 | In this example we used .times(1) instead of .once() and added the .at_least() modifier 115 | to demonstate that it is easy to match any number of calls, including 0 calls or a variable amount of 116 | calls. As you've probably guessed there is also an at_most() modifier. 117 | 118 | 119 | Spies 120 | ~~~~~ 121 | 122 | 123 | While replacing method calls with canned return values or checking that they are called with 124 | specific arguments is quite useful, there are also times when you want to execute the actual method 125 | and simply find out how many times it was called. flexmock uses should_call() to generate this 126 | sort of expectations instead of should_receive(): 127 | 128 | :: 129 | 130 | flexmock(Train).should_call("get_destination").once() 131 | 132 | 133 | In the above case the real get_destination() method will be executed, but flexmock will raise 134 | an exception unless it is executed exactly once. All the modifiers allowed with should_receive() 135 | can also be used with should_call() so it is possible to tweak the allowed arguments, return 136 | values and call times. 137 | 138 | :: 139 | 140 | (flexmock(Train) 141 | .should_call("set_destination") 142 | .once() 143 | .with_args(object, str, int) 144 | .and_raise(Exception, re.compile("^No such dest.*"))) 145 | 146 | 147 | The above example introduces a handful of new capabilities -- raising exceptions, matching argument types (object naturally matches any argument type) and regex matching on string return values and arguments. 148 | 149 | 150 | Summary 151 | ------- 152 | 153 | 154 | flexmock has many other features and capabilities, but hopefully the above overview has 155 | given you enough of the flavor for the kind of things that it makes possible. For more 156 | details see the `User Guide`_. 157 | 158 | .. _User Guide: user-guide.html 159 | -------------------------------------------------------------------------------- /docs/user-guide.rst: -------------------------------------------------------------------------------- 1 | Usage Documentation 2 | =================== 3 | 4 | Definitions 5 | ----------- 6 | 7 | In order to discuss flexmock usage it's important to define the 8 | following terms. 9 | 10 | :Stub: fake object that returns a canned value 11 | 12 | :Mock: fake object that returns a canned value and has an expectation, i.e. it includes a built-in assertion 13 | 14 | :Spy: watches method calls and records/verifies if the method is called with required parameters and/or returns expected values/exceptions 15 | 16 | Overview 17 | -------- 18 | 19 | flexmock declarations follow a consistent style of the following 3 forms: 20 | 21 | :: 22 | 23 | flexmock ( OBJECT ).COMMAND( ATTRIBUTE ).MODIFIER[.MODIFIER, ...] 24 | 25 | - or - 26 | 27 | flexmock ( OBJECT [, ATTRIBUTE=VALUE, ...] ) 28 | 29 | - or - 30 | 31 | flexmock ( ATTRIBUTE=VALUE [, ATTRIBUTE=VALUE,...] ) 32 | 33 | 34 | OBJECT: 35 | 36 | Either a module, a class, or an instance of a class 37 | 38 | COMMAND: 39 | 40 | One of should_receive, should_call, or new_instances. These 41 | create the initial expectation object. 42 | 43 | ATTRIBUTE: 44 | 45 | String name of an attribute 46 | 47 | MODIFIER: 48 | 49 | One of several Expectation modifiers, such as with_args, 50 | and_return, should_raise, times, etc. 51 | 52 | VALUE: 53 | 54 | Anything 55 | 56 | ----------- 57 | 58 | 59 | Example Usage 60 | ============= 61 | 62 | 63 | Setup 64 | ----- 65 | 66 | :: 67 | 68 | from flexmock import flexmock 69 | 70 | This will include flexmock in your test and make the necessary runner modifications 71 | so no further setup or cleanup is necessary. 72 | 73 | 74 | Fake objects 75 | ------------ 76 | 77 | :: 78 | 79 | fake = flexmock() # creates an object with no attributes 80 | 81 | Specify attribute/return value pairs 82 | 83 | :: 84 | 85 | fake_plane = flexmock( 86 | model="MIG-16", 87 | condition="used") 88 | 89 | Specify methods/return value pairs 90 | 91 | :: 92 | 93 | fake_plane = flexmock( 94 | fly=lambda: "voooosh!", 95 | land=lambda: "landed!") 96 | 97 | You can mix method and non-method attributes by making the return value a lambda for callable attributes. 98 | 99 | flexmock fake objects support the full range of flexmock commands but 100 | differ from partial mocks (described below) in that should_receive() 101 | can assign them new methods rather than being limited to acting on methods 102 | they already possess. 103 | 104 | :: 105 | 106 | fake_plane = flexmock(fly=lambda: "vooosh!") 107 | fake_plane.should_receive("land").and_return("landed!") 108 | 109 | 110 | Partial mocks 111 | ------------- 112 | 113 | flexmock provides three syntactic ways to hook into an existing object and override its methods. 114 | 115 | Mark the object as partially mocked, allowing it to be used to create new expectations 116 | 117 | :: 118 | 119 | flexmock(plane) 120 | plane.should_receive('fly').and_return('vooosh!').once() 121 | plane.should_receive('land').and_return('landed!').once() 122 | 123 | Equivalent syntax assigns the partially mocked object to a variable 124 | 125 | :: 126 | 127 | plane = flexmock(plane) 128 | plane.should_receive('fly').and_return('vooosh!').once() 129 | plane.should_receive('land').and_return('landed!').once() 130 | 131 | Or you can combine everything into one line if there is only one method to override 132 | 133 | :: 134 | 135 | flexmock(plane).should_receive('fly').and_return('vooosh!').once() 136 | 137 | You can also return the mock object after setting the expectations 138 | 139 | :: 140 | 141 | plane = flexmock(plane).should_receive('fly').and_return('vooosh!').mock() 142 | 143 | Note the "mock" modifier above -- the expectation chain returns an expectation otherwise 144 | 145 | :: 146 | 147 | plane.should_receive('land').with_args().and_return('foo', 'bar') 148 | 149 | 150 | :NOTE: If you do not provide a with_args() modifier then any set of arguments, including none, will be matched. However, if you specify with_args() the expectation will only match exactly zero arguments. 151 | 152 | :NOTE: If you do not provide a return value then None is returned by default. Thus, and_return() is equivalent to and_return(None) is equivalent to simply leaving off and_return. 153 | 154 | Attributes and properties 155 | ------------------------- 156 | 157 | Just as you're able to stub return values for functions and methods, flexmock also 158 | allows to stub out non-callable attributes and even (getter) properties. 159 | Syntax for this is exactly the same as for methods and functions. 160 | 161 | Shorthand 162 | --------- 163 | 164 | Instead of writing out the lengthy should_receive/and_return statements, you can 165 | also use the handy shorthand approach of passing them in as key=value pairs 166 | to the flexmock() function. For example, we can stub out two methods of the plane object 167 | in the same call: 168 | 169 | :: 170 | 171 | flexmock(plane, fly='voooosh!', land=('foo', 'bar')) 172 | 173 | This approach is handy and quick but only limited to stubs, i.e. 174 | it is not possible to further modify these kind of calls with any of 175 | the usual modifiers described below. 176 | 177 | Class level mocks 178 | ----------------- 179 | 180 | If the object your partially mock is a class, flexmock effectively replaces the 181 | method for all instances of that class. 182 | 183 | :: 184 | 185 | >>> class User: pass 186 | >>> flexmock(User) 187 | >>> User.should_receive('get_name').and_return('Bill Clinton') 188 | >>> bubba = User() 189 | >>> bubba.get_name() 190 | 'Bill Clinton' 191 | 192 | Automatically checked expectations 193 | ---------------------------------- 194 | 195 | Using the times(N) modifier, or its aliases -- once, twice, never -- 196 | allows you to create expectations that will be automatically checked by 197 | the test runner. 198 | 199 | Ensure fly('forward') gets called exactly three times 200 | 201 | :: 202 | 203 | (flexmock(plane) 204 | .should_receive('fly') 205 | .with_args('forward') 206 | .times(3)) 207 | 208 | Ensure turn('east') gets called at least twice 209 | 210 | :: 211 | 212 | (flexmock(plane) 213 | .should_receive('turn') 214 | .with_args('east') 215 | .at_least().twice()) 216 | 217 | Ensure land('airfield') gets called at most once 218 | 219 | :: 220 | 221 | (flexmock(plane) 222 | .should_receive('land') 223 | .with_args('airfield') 224 | .at_most().once()) 225 | 226 | Ensure that crash('boom!') is never called 227 | 228 | :: 229 | 230 | (flexmock(plane) 231 | .should_receive('crash') 232 | .with_args('boom!') 233 | .never()) 234 | 235 | Exceptions 236 | ---------- 237 | 238 | You can make the mocked method raise an exception instead of returning a value. 239 | 240 | :: 241 | 242 | (flexmock(plane) 243 | .should_receive('fly') 244 | .and_raise(BadWeatherException)) 245 | 246 | Or you can add a message to the exception being raised 247 | 248 | :: 249 | 250 | (flexmock(plane) 251 | .should_receive('fly') 252 | .and_raise(BadWeatherException, 'Oh noes, rain!')) 253 | 254 | 255 | Spies (proxies) 256 | --------------- 257 | 258 | In addition to stubbing out a given method and returning fake values, 259 | flexmock also allows you to call the original method and make 260 | expectations based on its return values/exceptions and the number of 261 | times the method is called with the given arguments. 262 | 263 | Matching specific arguments 264 | 265 | :: 266 | 267 | (flexmock(plane) 268 | .should_call('repair') 269 | .with_args(wing, cockpit) 270 | .once()) 271 | 272 | Matching any arguments 273 | 274 | :: 275 | 276 | (flexmock(plane) 277 | .should_call('turn') 278 | .twice()) 279 | 280 | Matching specific return values 281 | 282 | :: 283 | 284 | (flexmock(plane) 285 | .should_call('land') 286 | .and_return('landed!')) 287 | 288 | Matching a regular expression 289 | 290 | :: 291 | 292 | (flexmock(plane) 293 | .should_call('land') 294 | .and_return(re.compile('^la'))) 295 | 296 | Match return values by class/type 297 | 298 | :: 299 | 300 | (flexmock(plane) 301 | .should_call('fly') 302 | .and_return(str, object, None)) 303 | 304 | Ensure that an appropriate exception is raised 305 | 306 | :: 307 | 308 | (flexmock(plane) 309 | .should_call('fly') 310 | .and_raise(BadWeatherException)) 311 | 312 | Check that the exception message matches your expectations 313 | 314 | :: 315 | 316 | (flexmock(plane) 317 | .should_call('fly') 318 | .and_raise(BadWeatherException, 'Oh noes, rain!')) 319 | 320 | Check that the exception message matches a regular expression 321 | 322 | :: 323 | 324 | (flexmock(plane) 325 | .should_call('fly') 326 | .and_raise(BadWeatherException, re.compile('rain'))) 327 | 328 | If either and_return() or and_raise() is provided, flexmock will 329 | verify that the return value matches the expected return value or 330 | exception. 331 | 332 | :NOTE: should_call() changes the behavior of and_return() and and_raise() to specify expectations rather than generate given values or exceptions. 333 | 334 | Multiple return values 335 | ---------------------- 336 | 337 | It's possible for the mocked method to return different values on successive calls. 338 | 339 | :: 340 | 341 | >>> flexmock(group).should_receive('get_member').and_return('user1').and_return('user2').and_return('user3') 342 | >>> group.get_member() 343 | 'user1' 344 | >>> group.get_member() 345 | 'user2' 346 | >>> group.get_member() 347 | 'user3' 348 | 349 | Or use the short-hand form 350 | 351 | :: 352 | 353 | (flexmock(group) 354 | .should_receive('get_member') 355 | .and_return('user1', 'user2', 'user3') 356 | .one_by_one()) 357 | 358 | You can also mix return values with exception raises 359 | 360 | :: 361 | 362 | (flexmock(group) 363 | .should_receive('get_member') 364 | .and_return('user1') 365 | .and_raise(Exception) 366 | .and_return('user2')) 367 | 368 | Fake new instances 369 | ------------------ 370 | 371 | Occasionally you will want a class to create fake objects when it's 372 | being instantiated. flexmock makes it easy and painless. 373 | 374 | Your first option is to simply replace the class with a function. 375 | 376 | 377 | :: 378 | (flexmock(some_module) 379 | .should_receive('NameOfClass') 380 | .and_return(fake_instance)) 381 | # fake_instance can be created with flexmock as well 382 | 383 | The upside of this approach is that it works for both new-style and old-style 384 | classes. The downside is that you may run into subtle issues since the 385 | class has now been replaced by a function. 386 | 387 | If you're dealing with new-style classes, flexmock offers another alternative using the .new_instances() command. 388 | 389 | :: 390 | 391 | >>> class Group(object): pass 392 | >>> fake_group = flexmock(name='fake') 393 | >>> flexmock(Group).new_instances(fake_group) 394 | >>> Group().name == 'fake' 395 | True 396 | 397 | It is also possible to return different fake objects in a sequence. 398 | 399 | :: 400 | 401 | >>> class Group(object): pass 402 | >>> fake_group1 = flexmock(name='fake') 403 | >>> fake_group2 = flexmock(name='real') 404 | >>> flexmock(Group).new_instances(fake_group1, fake_group2) 405 | >>> Group().name == 'fake' 406 | True 407 | >>> Group().name == 'real' 408 | True 409 | 410 | Another approach, if you're familiar with how instance instatiation is done in Python, is to stub the __new__ method directly. 411 | 412 | :: 413 | 414 | >>> flexmock(Group).should_receive('__new__').and_return(fake_group) 415 | >>> # or, if you want to be even slicker 416 | >>> flexmock(Group, __new__=fake_group) 417 | 418 | In fact, the new_instances command is simply shorthand for should_receive('__new__').and_return() under the hood. 419 | 420 | Generators 421 | ---------- 422 | 423 | In addition to returning values and raising exceptions, flexmock can also turn 424 | the mocked method into a generator that yields successive values. 425 | 426 | :: 427 | 428 | >>> flexmock(plane).should_receive('flight_log').and_yield('take off', 'flight', 'landing') 429 | >>> for i in plane.flight_log(): 430 | >>> print i 431 | 'take off' 432 | 'flight' 433 | 'landing' 434 | 435 | You can also use Python's builtin iter() function to generate an iterable return value. 436 | 437 | :: 438 | 439 | flexmock(plane, flight_log=iter(['take off', 'flight', 'landing'])) 440 | 441 | In fact, the and_yield() modifier is just shorthand for should_receive().and_return(iter) 442 | under the hood. 443 | 444 | 445 | Private methods 446 | --------------- 447 | 448 | One of the small pains of writing unit tests is that it can be 449 | difficult to get at the private methods since Python "conveniently" 450 | renames them when you try to access them from outside the object. With 451 | flexmock there is nothing special you need to do to -- mocking private 452 | methods is exactly the same as any other methods. 453 | 454 | Call order 455 | ---------- 456 | 457 | flexmock does not enforce call order by default, but it's easy to do if you need to. 458 | 459 | :: 460 | 461 | (flexmock(plane) 462 | .should_receive('fly') 463 | .with_args('forward') 464 | .and_return('ok') 465 | .ordered()) 466 | (flexmock(plane) 467 | .should_receive('fly') 468 | .with_args('up') 469 | .and_return('ok') 470 | .ordered()) 471 | 472 | The order of the flexmock calls is the order in which these methods will need to be 473 | called by the code under test. 474 | 475 | If method fly() above is called with the right arguments in the declared order things 476 | will be fine and both will return 'ok'. 477 | But trying to call fly('up') before fly('forward') will result in an exception. 478 | 479 | State Support 480 | ------------- 481 | 482 | flexmock supports conditional method execution based on external state. 483 | Consider the rather contrived Radio class with the following methods: 484 | 485 | :: 486 | 487 | >>> class Radio: 488 | ... is_on = False 489 | ... def switch_on(self): self.is_on = True 490 | ... def switch_off(self): self.is_on = False 491 | ... def select_channel(self): return None 492 | ... def adjust_volume(self, num): self.volume = num 493 | >>> radio = Radio() 494 | 495 | Now we can define some method call expectations dependent on the state of the radio: 496 | 497 | :: 498 | 499 | >>> flexmock(radio) 500 | >>> radio.should_receive('select_channel').once().when(lambda: radio.is_on) 501 | >>> radio.should_call('adjust_volume').once().with_args(5).when(lambda: radio.is_on) 502 | 503 | 504 | Calling these while the radio is off will result in an error: 505 | 506 | :: 507 | 508 | >>> radio.select_channel() 509 | Traceback (most recent call last): 510 | File "", line 1, in 511 | File "flexmock.py", line 674, in mock_method 512 | (method, expectation._get_runnable())) 513 | flexmock.StateError: select_channel expected to be called when condition is True 514 | 515 | >>> radio.adjust_volume(5) 516 | Traceback (most recent call last): 517 | File "", line 1, in 518 | File "flexmock.py", line 674, in mock_method 519 | (method, expectation._get_runnable())) 520 | flexmock.StateError: adjust_volume expected to be called when condition is True 521 | Traceback (most recent call last): 522 | 523 | Turning the radio on will make things work as expected: 524 | 525 | :: 526 | 527 | >>> radio.is_on = True 528 | >>> radio.select_channel() 529 | >>> radio.adjust_volume(5) 530 | 531 | 532 | 533 | Chained methods 534 | --------------- 535 | 536 | Let's say you have some code that looks something like the following: 537 | 538 | :: 539 | 540 | http = HTTP() 541 | results = (http.get_url('http://www.google.com') 542 | .parse_html() 543 | .display_results()) 544 | 545 | You could use flexmock to mock each of these method calls individually: 546 | 547 | :: 548 | 549 | mock = flexmock(get_url=lambda: flexmock(parse_html=lambda: flexmock(display_results='ok'))) 550 | flexmock(HTTP).new_instances(mock) 551 | 552 | But that looks really error prone and quite difficult to parse when 553 | reading. Here's a better way: 554 | 555 | :: 556 | 557 | mock = flexmock() 558 | flexmock(HTTP).new_instances(mock) 559 | mock.should_receive('get_url.parse_html.display_results').and_return('ok') 560 | 561 | When using this short-hand, flexmock will create intermediate objects 562 | and expectations, returning the final one in the chain. As a result, any 563 | further modifications, such as with_args() or times() modifiers, will 564 | only be applied to the final method in the chain. If you need finer 565 | grained control, such as specifying specific arguments to an 566 | intermediate method, you can always fall back to the above long version. 567 | 568 | Word of caution: because flexmock generates temporary intermediate mock objects 569 | for each step along the chain, trying to mock two method call chains with the 570 | same prefix will not work. That is, doing the following will fail to set up 571 | the stub for display_results() because the one for save_results() overrides it: 572 | 573 | :: 574 | 575 | flexmock(HTTP).should_receive('get_url.parse_html.display_results').and_return('ok') 576 | flexmock(HTTP).should_receive('get_url.parse_html.save_results').and_return('ok') 577 | 578 | In this situation, you should identify the point where the chain starts to 579 | diverge and return a flexmock() object that handles all the "tail" 580 | methods using the same object: 581 | 582 | :: 583 | 584 | (flexmock(HTTP) 585 | .should_receive('get_url.parse_html') 586 | .and_return(flexmock, display_results='ok', save_results='ok')) 587 | 588 | 589 | Replacing methods 590 | ----------------- 591 | 592 | There are times when it is useful to replace a method with a custom lambda or 593 | function, rather than simply stubbing it out, in order to return custom values 594 | based on provided arguments or a global value that changes between method calls. 595 | 596 | :: 597 | 598 | (flexmock(plane) 599 | .should_receive('set_speed') 600 | .replace_with(lambda x: x == 5)) 601 | 602 | There is also shorthand for this, similar to the shorthand for should_receive/and_return: 603 | 604 | :: 605 | 606 | flexmock(plane, set_speed=lambda x: x == 5) 607 | 608 | :NOTE: Whenever the return value provided to the key=value shorthand is a callable (such as lambda), flexmock expands it to should_receive().replace_with() rather than should_receive().and_return(). 609 | 610 | .. _builtin_functions: 611 | 612 | Builtin functions 613 | ----------------- 614 | 615 | Mocking or stubbing out builtin functions, such as open(), can be slightly tricky. 616 | The "builtins" module is accessed differently in interactive Python sessions versus 617 | running applications and named differently in Python 3.0 and above. 618 | 619 | It is also not always obvious when the builtin function you are trying to mock might be 620 | internally called by the test runner and cause unexpected behavior in the test. 621 | As a result, the recommended way to mock out builtin functions is to always specify 622 | a fall-through with should_call() first and use with_args() to limit the scope of 623 | your mock or stub to just the specific invocation you are trying to replace: 624 | 625 | :: 626 | 627 | # python 2.4+ 628 | mock = flexmock(sys.modules['__builtin__']) 629 | mock.should_call('open') # set the fall-through 630 | (mock.should_receive('open') 631 | .with_args('/your/file') 632 | .and_return( flexmock(read=lambda: 'file contents') )) 633 | 634 | # python 3.0+ 635 | mock = flexmock(sys.modules['builtins']) 636 | mock.should_call('open') # set the fall-through 637 | (mock.should_receive('open') 638 | .with_args('/your/file') 639 | .and_return( flexmock(read=lambda: 'file contents') )) 640 | 641 | 642 | Expectation Matching 643 | ==================== 644 | 645 | Creating an expectation with no arguments will by default match all 646 | arguments, including no arguments. 647 | 648 | :: 649 | 650 | >>> flexmock(plane).should_receive('fly').and_return('ok') 651 | 652 | Will be matched by any of the following: 653 | 654 | :: 655 | 656 | >>> plane.fly() 657 | 'ok' 658 | >>> plane.fly('up') 659 | 'ok' 660 | >>> plane.fly('up', 'down') 661 | 'ok' 662 | 663 | You can also match exactly no arguments 664 | 665 | :: 666 | 667 | (flexmock(plane) 668 | .should_receive('fly') 669 | .with_args()) 670 | 671 | Or match any single argument 672 | 673 | :: 674 | 675 | (flexmock(plane) 676 | .should_receive('fly') 677 | .with_args(object)) 678 | 679 | :NOTE: In addition to exact values, you can match against the type or class of the argument. 680 | 681 | Match any single string argument 682 | 683 | :: 684 | 685 | (flexmock(plane) 686 | .should_receive('fly') 687 | .with_args(str)) 688 | 689 | Match the empty string using a compiled regular expression 690 | 691 | :: 692 | 693 | regex = re.compile('^(up|down)$') 694 | (flexmock(plane) 695 | .should_receive('fly') 696 | .with_args(regex)) 697 | 698 | Match any set of three arguments where the first one is an integer, 699 | second one is anything, and third is string 'foo' 700 | (matching against user defined classes is also supported in the same fashion) 701 | 702 | :: 703 | 704 | (flexmock(plane) 705 | .should_receive('repair') 706 | .with_args(int, object, 'notes')) 707 | 708 | And if the default argument matching based on types is not flexible enough, 709 | flexmock will respect matcher objects that provide a custom __eq__ method. 710 | 711 | For example, when trying to match against contents of numpy arrays, 712 | equality is undefined by the library so comparing two of them directly 713 | is meaningless unless you use all() or any() on the return value of the comparison. 714 | 715 | What you can do in this case is create a custom matcher object and flexmock will 716 | use its __eq__ method when comparing the arguments at runtime. 717 | 718 | :: 719 | 720 | class NumpyArrayMatcher(object): 721 | def __init__(self, array): self.array = array 722 | def __eq__(self, other): return all(other == self.array) 723 | 724 | (flexmock(obj) 725 | .should_receive('function') 726 | .with_args(NumpyArrayMatcher(array1))) 727 | 728 | The above approach will work for any objects that choose not to return proper 729 | boolean comparison values, or if you simply find the default equality and 730 | type-based matching not sufficiently specific. 731 | 732 | It is, of course, also possible to create multiple expectations for the same 733 | method differentiated by arguments. 734 | 735 | :: 736 | 737 | >>> flexmock(plane).should_receive('fly').and_return('ok') 738 | >>> flexmock(plane).should_receive('fly').with_args('up').and_return('bad') 739 | 740 | Try to excecute plane.fly() with any, or no, arguments as defined by the first 741 | flexmock call will return the first value. 742 | 743 | :: 744 | 745 | >>> plane.fly() 746 | 'ok' 747 | >>> plane.fly('forward', 'down') 748 | 'ok' 749 | 750 | But! If argument values match the more specific flexmock call the function 751 | will return the other return value. 752 | 753 | :: 754 | 755 | >>> plane.fly('up') 756 | 'bad' 757 | 758 | The order of the expectations being defined is significant, with later 759 | expectations having higher precedence than previous ones. Which means 760 | that if you reversed the order of the example expectations above the 761 | more specific expectation would never be matched. 762 | 763 | Style 764 | ===== 765 | 766 | While the order of modifiers is unimportant to flexmock, there is a preferred convention 767 | that will make your tests more readable. 768 | 769 | If using with_args(), place it before should_return(), and_raise() and and_yield() modifiers: 770 | 771 | :: 772 | 773 | (flexmock(plane) 774 | .should_receive('fly') 775 | .with_args('up', 'down') 776 | .and_return('ok')) 777 | 778 | If using the times() modifier (or its aliases: once, twice, never), place them at 779 | the end of the flexmock statement: 780 | 781 | :: 782 | 783 | (flexmock(plane) 784 | .should_receive('fly') 785 | .and_return('ok') 786 | .once()) 787 | -------------------------------------------------------------------------------- /flexmock.py: -------------------------------------------------------------------------------- 1 | """Copyright 2011-2015 Herman Sheremetyev, Slavek Kabrda. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 15 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 16 | EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 18 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 20 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 21 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | """ 24 | 25 | 26 | # from flexmock import * is evil, keep it from doing any damage 27 | __all__ = ['flexmock'] 28 | 29 | 30 | import inspect 31 | import re 32 | import sys 33 | import types 34 | 35 | 36 | AT_LEAST = 'at least' 37 | AT_MOST = 'at most' 38 | EXACTLY = 'exactly' 39 | UPDATED_ATTRS = ['should_receive', 'should_call', 'new_instances'] 40 | DEFAULT_CLASS_ATTRIBUTES = [attr for attr in dir(type) 41 | if attr not in dir(type('', (object,), {}))] 42 | RE_TYPE = re.compile('') 43 | SPECIAL_METHODS = (classmethod, staticmethod) 44 | 45 | 46 | try: 47 | any([]) 48 | except NameError: 49 | # Python 2.4 sucks 50 | def any(iterable): 51 | for x in iterable: 52 | if x: return True 53 | return False 54 | 55 | 56 | class FlexmockError(Exception): 57 | pass 58 | 59 | 60 | class MockBuiltinError(Exception): 61 | pass 62 | 63 | 64 | class MethodSignatureError(FlexmockError): 65 | pass 66 | 67 | 68 | class ExceptionClassError(FlexmockError): 69 | pass 70 | 71 | 72 | class ExceptionMessageError(FlexmockError): 73 | pass 74 | 75 | 76 | class StateError(FlexmockError): 77 | pass 78 | 79 | 80 | class MethodCallError(FlexmockError): 81 | pass 82 | 83 | 84 | class CallOrderError(FlexmockError): 85 | pass 86 | 87 | 88 | class ReturnValue(object): 89 | def __init__(self, value=None, raises=None): 90 | self.value = value 91 | self.raises = raises 92 | 93 | def __str__(self): 94 | if self.raises: 95 | return '%s(%s)' % (self.raises, _arg_to_str(self.value)) 96 | else: 97 | if not isinstance(self.value, tuple): 98 | return '%s' % _arg_to_str(self.value) 99 | elif len(self.value) == 1: 100 | return '%s' % _arg_to_str(self.value[0]) 101 | else: 102 | return '(%s)' % ', '.join([_arg_to_str(x) for x in self.value]) 103 | 104 | 105 | class FullArgSpec(object): 106 | """Silly hack for inpsect.getargspec return a tuple on python <2.6""" 107 | def __init__(self, spec): 108 | if len(spec) == 4: # python2 => getargspec was used 109 | spec += ([], None, {}) 110 | (self.args, self.varargs, self.keywords, self.defaults, self.kwonlyargs, 111 | self.kwonlydefaults, self.annotations) = spec 112 | 113 | class FlexmockContainer(object): 114 | """Holds global hash of object/expectation mappings.""" 115 | flexmock_objects = {} 116 | properties = {} 117 | ordered = [] 118 | last = None 119 | 120 | @classmethod 121 | def reset(cls): 122 | cls.ordered = [] 123 | cls.last = None 124 | cls.flexmock_objects = {} 125 | cls.properties = {} 126 | 127 | @classmethod 128 | def get_flexmock_expectation(cls, obj, name=None, args=None): 129 | """Retrieves an existing matching expectation.""" 130 | if args == None: 131 | args = {'kargs': (), 'kwargs': {}} 132 | if not isinstance(args, dict): 133 | args = {'kargs': args, 'kwargs': {}} 134 | if not isinstance(args['kargs'], tuple): 135 | args['kargs'] = (args['kargs'],) 136 | if name and obj in cls.flexmock_objects: 137 | found = None 138 | for e in reversed(cls.flexmock_objects[obj]): 139 | if e.name == name and e.match_args(args): 140 | if e in cls.ordered or not e._ordered and not found: 141 | found = e 142 | if found and found._ordered: 143 | cls._verify_call_order(found, args) 144 | return found 145 | 146 | @classmethod 147 | def _verify_call_order(cls, expectation, args): 148 | if not cls.ordered: 149 | next_method = cls.last 150 | else: 151 | next_method = cls.ordered.pop(0) 152 | cls.last = next_method 153 | if expectation is not next_method: 154 | raise CallOrderError( 155 | '%s called before %s' % 156 | (_format_args(expectation.name, args), 157 | _format_args(next_method.name, next_method.args))) 158 | 159 | @classmethod 160 | def add_expectation(cls, obj, expectation): 161 | if obj in cls.flexmock_objects: 162 | cls.flexmock_objects[obj].append(expectation) 163 | else: 164 | cls.flexmock_objects[obj] = [expectation] 165 | 166 | @classmethod 167 | def add_teardown_property(cls, obj, name): 168 | if obj in cls.properties: 169 | cls.properties[obj].append(name) 170 | else: 171 | cls.properties[obj] = [name] 172 | 173 | @classmethod 174 | def teardown_properties(cls): 175 | for obj, names in cls.properties.items(): 176 | for name in names: 177 | delattr(obj, name) 178 | 179 | 180 | class Expectation(object): 181 | """Holds expectations about methods. 182 | 183 | The information contained in the Expectation object includes method name, 184 | its argument list, return values, and any exceptions that the method might 185 | raise. 186 | """ 187 | 188 | def __init__(self, mock, name=None, return_value=None, original=None): 189 | self.name = name 190 | self.modifier = EXACTLY 191 | if original is not None: 192 | self.original = original 193 | self.args = None 194 | self.method_type = types.MethodType 195 | self.argspec = None 196 | value = ReturnValue(return_value) 197 | self.return_values = return_values = [] 198 | self._replace_with = None 199 | if return_value is not None: 200 | return_values.append(value) 201 | self.times_called = 0 202 | self.expected_calls = { 203 | EXACTLY: None, 204 | AT_LEAST: None, 205 | AT_MOST: None} 206 | self.runnable = lambda: True 207 | self._mock = mock 208 | self._pass_thru = False 209 | self._ordered = False 210 | self._one_by_one = False 211 | self._verified = False 212 | self._callable = True 213 | self._local_override = False 214 | 215 | def __str__(self): 216 | return '%s -> (%s)' % (_format_args(self.name, self.args), 217 | ', '.join(['%s' % x for x in self.return_values])) 218 | 219 | def __call__(self): 220 | return self 221 | 222 | def __getattribute__(self, name): 223 | if name == 'once': 224 | return _getattr(self, 'times')(1) 225 | elif name == 'twice': 226 | return _getattr(self, 'times')(2) 227 | elif name == 'never': 228 | return _getattr(self, 'times')(0) 229 | elif name in ('at_least', 'at_most', 'ordered', 'one_by_one'): 230 | return _getattr(self, name)() 231 | elif name == 'mock': 232 | return _getattr(self, 'mock')() 233 | else: 234 | return _getattr(self, name) 235 | 236 | def __getattr__(self, name): 237 | self.__raise( 238 | AttributeError, 239 | "'%s' object has not attribute '%s'" % (self.__class__.__name__, name)) 240 | 241 | def _get_runnable(self): 242 | """Ugly hack to get the name of when() condition from the source code.""" 243 | name = 'condition' 244 | try: 245 | source = inspect.getsource(self.runnable) 246 | if 'when(' in source: 247 | name = source.split('when(')[1].split(')')[0] 248 | elif 'def ' in source: 249 | name = source.split('def ')[1].split('(')[0] 250 | except: # couldn't get the source, oh well 251 | pass 252 | return name 253 | 254 | def _verify_signature_match(self, *kargs, **kwargs): 255 | if isinstance(self._mock, Mock): 256 | return # no sense in enforcing this for fake objects 257 | allowed = self.argspec 258 | # TODO(herman): fix it properly so that module mocks aren't set as methods 259 | is_method = (inspect.ismethod(getattr(self._mock, self.name)) and 260 | self.method_type is not staticmethod and 261 | type(self._mock) != types.ModuleType) 262 | args_len = len(allowed.args) 263 | if is_method: 264 | args_len -= 1 265 | minimum = args_len - (allowed.defaults and len(allowed.defaults) or 0) 266 | maximum = None 267 | if allowed.varargs is None and allowed.keywords is None: 268 | maximum = args_len 269 | total_positional = len( 270 | kargs + tuple(a for a in kwargs if a in allowed.args)) 271 | named_optionals = [a for a in kwargs 272 | if allowed.defaults 273 | if a in allowed.args[len(allowed.args) - len(allowed.defaults):]] 274 | if allowed.defaults and total_positional == minimum and named_optionals: 275 | minimum += len(named_optionals) 276 | if total_positional < minimum: 277 | raise MethodSignatureError( 278 | '%s requires at least %s arguments, expectation provided %s' % 279 | (self.name, minimum, total_positional)) 280 | if maximum is not None and total_positional > maximum: 281 | raise MethodSignatureError( 282 | '%s requires at most %s arguments, expectation provided %s' % 283 | (self.name, maximum, total_positional)) 284 | if args_len == len(kargs) and any(a for a in kwargs if a in allowed.args): 285 | raise MethodSignatureError( 286 | '%s already given as positional arguments to %s' % 287 | ([a for a in kwargs if a in allowed.args], self.name)) 288 | if (not allowed.keywords and 289 | any(a for a in kwargs if a not in allowed.args + allowed.kwonlyargs)): 290 | raise MethodSignatureError( 291 | '%s is not a valid keyword argument to %s' % 292 | ([a for a in kwargs 293 | if a not in (allowed.args + allowed.kwonlyargs)][0], self.name)) 294 | # check that kwonlyargs that don't have default value specified are provided 295 | required_kwonlyargs = [a for a in allowed.kwonlyargs 296 | if a not in (allowed.kwonlydefaults or {})] 297 | missing_kwonlyargs = [a for a in required_kwonlyargs if a not in kwargs] 298 | if missing_kwonlyargs: 299 | raise MethodSignatureError( 300 | '%s requires keyword-only argument(s) "%s"' % 301 | (self.name, '", "'.join(missing_kwonlyargs))) 302 | 303 | 304 | def _update_original(self, name, obj): 305 | if hasattr(obj, '__dict__') and name in obj.__dict__: 306 | self.original = obj.__dict__[name] 307 | else: 308 | self.original = getattr(obj, name) 309 | self._update_argspec() 310 | 311 | def _update_argspec(self): 312 | original = self.__dict__.get('original') 313 | if original: 314 | try: 315 | if sys.version_info < (3, 0): 316 | self.argspec = FullArgSpec(inspect.getargspec(original)) 317 | else: 318 | self.argspec = FullArgSpec(inspect.getfullargspec(original)) 319 | except TypeError: 320 | # built-in function: fall back to stupid processing and hope the 321 | # builtins don't change signature 322 | pass 323 | 324 | def _normalize_named_args(self, *kargs, **kwargs): 325 | argspec = self.argspec 326 | default = {'kargs': kargs, 'kwargs': kwargs} 327 | if not argspec: 328 | return default 329 | ret = {'kargs': (), 'kwargs': kwargs} 330 | if inspect.ismethod(self.original): 331 | args = argspec.args[1:] 332 | else: 333 | args = argspec.args 334 | for i, arg in enumerate(kargs): 335 | if len(args) <= i: return default 336 | ret['kwargs'][args[i]] = arg 337 | return ret 338 | 339 | def __raise(self, exception, message): 340 | """Safe internal raise implementation. 341 | 342 | In case we're patching builtins, it's important to reset the 343 | expectation before raising any exceptions or else things like 344 | open() might be stubbed out and the resulting runner errors are very 345 | difficult to diagnose. 346 | """ 347 | self.reset() 348 | raise exception(message) 349 | 350 | def match_args(self, given_args): 351 | """Check if the set of given arguments matches this expectation.""" 352 | expected_args = self.args 353 | given_args = self._normalize_named_args( 354 | *given_args['kargs'], **given_args['kwargs']) 355 | if (expected_args == given_args or expected_args is None): 356 | return True 357 | if (len(given_args['kargs']) != len(expected_args['kargs']) or 358 | len(given_args['kwargs']) != len(expected_args['kwargs']) or 359 | (sorted(given_args['kwargs'].keys()) != 360 | sorted(expected_args['kwargs'].keys()))): 361 | return False 362 | for i, arg in enumerate(given_args['kargs']): 363 | if not _arguments_match(arg, expected_args['kargs'][i]): 364 | return False 365 | for k, v in given_args['kwargs'].items(): 366 | if not _arguments_match(v, expected_args['kwargs'][k]): 367 | return False 368 | return True 369 | 370 | def mock(self): 371 | """Return the mock associated with this expectation.""" 372 | return self._mock 373 | 374 | def with_args(self, *kargs, **kwargs): 375 | """Override the arguments used to match this expectation's method. 376 | 377 | Args: 378 | - kargs: optional keyword arguments 379 | - kwargs: optional named arguments 380 | 381 | Returns: 382 | - self, i.e. can be chained with other Expectation methods 383 | """ 384 | if not self._callable: 385 | self.__raise(FlexmockError, "can't use with_args() with attribute stubs") 386 | self._update_argspec() 387 | if self.argspec: 388 | # do this outside try block as TypeError is way too general and catches 389 | # unrelated errors in the verify signature code 390 | self._verify_signature_match(*kargs, **kwargs) 391 | self.args = self._normalize_named_args(*kargs, **kwargs) 392 | else: 393 | self.args = {'kargs': kargs, 'kwargs': kwargs} 394 | return self 395 | 396 | def and_return(self, *values): 397 | """Override the return value of this expectation's method. 398 | 399 | When and_return is given multiple times, each value provided is returned 400 | on successive invocations of the method. It is also possible to mix 401 | and_return with and_raise in the same manner to alternate between returning 402 | a value and raising and exception on different method invocations. 403 | 404 | When combined with the one_by_one property, value is treated as a list of 405 | values to be returned in the order specified by successive calls to this 406 | method rather than a single list to be returned each time. 407 | 408 | Args: 409 | - values: optional list of return values, defaults to None if not given 410 | 411 | Returns: 412 | - self, i.e. can be chained with other Expectation methods 413 | """ 414 | if not values: 415 | value = None 416 | elif len(values) == 1: 417 | value = values[0] 418 | else: 419 | value = values 420 | 421 | if not self._callable: 422 | _setattr(self._mock, self.name, value) 423 | return self 424 | 425 | return_values = _getattr(self, 'return_values') 426 | if not _getattr(self, '_one_by_one'): 427 | value = ReturnValue(value) 428 | return_values.append(value) 429 | else: 430 | try: 431 | return_values.extend([ReturnValue(v) for v in value]) 432 | except TypeError: 433 | return_values.append(ReturnValue(value)) 434 | return self 435 | 436 | def times(self, number): 437 | """Number of times this expectation's method is expected to be called. 438 | 439 | There are also 3 aliases for the times() method: 440 | 441 | - once() -> times(1) 442 | - twice() -> times(2) 443 | - never() -> times(0) 444 | 445 | Args: 446 | - number: int 447 | 448 | Returns: 449 | - self, i.e. can be chained with other Expectation methods 450 | """ 451 | if not self._callable: 452 | self.__raise(FlexmockError, "can't use times() with attribute stubs") 453 | expected_calls = _getattr(self, 'expected_calls') 454 | modifier = _getattr(self, 'modifier') 455 | expected_calls[modifier] = number 456 | return self 457 | 458 | def one_by_one(self): 459 | """Modifies the return value to be treated as a list of return values. 460 | 461 | Each value in the list is returned on successive invocations of the method. 462 | 463 | Returns: 464 | - self, i.e. can be chained with other Expectation methods 465 | """ 466 | if not self._callable: 467 | self.__raise(FlexmockError, "can't use one_by_one() with attribute stubs") 468 | if not self._one_by_one: 469 | self._one_by_one = True 470 | return_values = _getattr(self, 'return_values') 471 | saved_values = return_values[:] 472 | self.return_values = return_values = [] 473 | for value in saved_values: 474 | try: 475 | for val in value.value: 476 | return_values.append(ReturnValue(val)) 477 | except TypeError: 478 | return_values.append(value) 479 | return self 480 | 481 | def at_least(self): 482 | """Modifies the associated times() expectation. 483 | 484 | When given, an exception will only be raised if the method is called less 485 | than times() specified. Does nothing if times() is not given. 486 | 487 | Returns: 488 | - self, i.e. can be chained with other Expectation methods 489 | """ 490 | if not self._callable: 491 | self.__raise(FlexmockError, "can't use at_least() with attribute stubs") 492 | expected_calls = _getattr(self, 'expected_calls') 493 | modifier = _getattr(self, 'modifier') 494 | if expected_calls[AT_LEAST] is not None or modifier == AT_LEAST: 495 | self.__raise(FlexmockError, 'cannot use at_least modifier twice') 496 | if modifier == AT_MOST and expected_calls[AT_MOST] is None: 497 | self.__raise(FlexmockError, 'cannot use at_least with at_most unset') 498 | self.modifier = AT_LEAST 499 | return self 500 | 501 | def at_most(self): 502 | """Modifies the associated "times" expectation. 503 | 504 | When given, an exception will only be raised if the method is called more 505 | than times() specified. Does nothing if times() is not given. 506 | 507 | Returns: 508 | - self, i.e. can be chained with other Expectation methods 509 | """ 510 | if not self._callable: 511 | self.__raise(FlexmockError, "can't use at_most() with attribute stubs") 512 | expected_calls = _getattr(self, 'expected_calls') 513 | modifier = _getattr(self, 'modifier') 514 | if expected_calls[AT_MOST] is not None or modifier == AT_MOST: 515 | self.__raise(FlexmockError, 'cannot use at_most modifier twice') 516 | if modifier == AT_LEAST and expected_calls[AT_LEAST] is None: 517 | self.__raise(FlexmockError, 'cannot use at_most with at_least unset') 518 | self.modifier = AT_MOST 519 | return self 520 | 521 | def ordered(self): 522 | """Makes the expectation respect the order of should_receive statements. 523 | 524 | An exception will be raised if methods are called out of order, determined 525 | by order of should_receive calls in the test. 526 | 527 | Returns: 528 | - self, i.e. can be chained with other Expectation methods 529 | """ 530 | if not self._callable: 531 | self.__raise(FlexmockError, "can't use ordered() with attribute stubs") 532 | self._ordered = True 533 | FlexmockContainer.ordered.append(self) 534 | return self 535 | 536 | def when(self, func): 537 | """Sets an outside resource to be checked before executing the method. 538 | 539 | Args: 540 | - func: function to call to check if the method should be executed 541 | 542 | Returns: 543 | - self, i.e. can be chained with other Expectation methods 544 | """ 545 | if not self._callable: 546 | self.__raise(FlexmockError, "can't use when() with attribute stubs") 547 | if not hasattr(func, '__call__'): 548 | self.__raise(FlexmockError, 'when() parameter must be callable') 549 | self.runnable = func 550 | return self 551 | 552 | def and_raise(self, exception, *kargs, **kwargs): 553 | """Specifies the exception to be raised when this expectation is met. 554 | 555 | Args: 556 | - exception: class or instance of the exception 557 | - kargs: optional keyword arguments to pass to the exception 558 | - kwargs: optional named arguments to pass to the exception 559 | 560 | Returns: 561 | - self, i.e. can be chained with other Expectation methods 562 | """ 563 | if not self._callable: 564 | self.__raise(FlexmockError, "can't use and_raise() with attribute stubs") 565 | args = {'kargs': kargs, 'kwargs': kwargs} 566 | return_values = _getattr(self, 'return_values') 567 | return_values.append(ReturnValue(raises=exception, value=args)) 568 | return self 569 | 570 | def replace_with(self, function): 571 | """Gives a function to run instead of the mocked out one. 572 | 573 | Args: 574 | - function: callable 575 | 576 | Returns: 577 | - self, i.e. can be chained with other Expectation methods 578 | """ 579 | if not self._callable: 580 | self.__raise(FlexmockError, 581 | "can't use replace_with() with attribute/property stubs") 582 | replace_with = _getattr(self, '_replace_with') 583 | original = self.__dict__.get('original') 584 | if replace_with: 585 | self.__raise(FlexmockError, 'replace_with cannot be specified twice') 586 | if function == original: 587 | self._pass_thru = True 588 | self._replace_with = function 589 | return self 590 | 591 | def and_yield(self, *kargs): 592 | """Specifies the list of items to be yielded on successive method calls. 593 | 594 | In effect, the mocked object becomes a generator. 595 | 596 | Returns: 597 | - self, i.e. can be chained with other Expectation methods 598 | """ 599 | if not self._callable: 600 | self.__raise( 601 | FlexmockError, "can't use and_yield() with attribute stubs") 602 | return self.and_return(iter(kargs)) 603 | 604 | def verify(self, final=True): 605 | """Verify that this expectation has been met. 606 | 607 | Args: 608 | final: boolean, True if no further calls to this method expected 609 | (skip checking at_least expectations when False) 610 | 611 | Raises: 612 | MethodCallError Exception 613 | """ 614 | failed, message = self._verify_number_of_calls(final) 615 | if failed and not self._verified: 616 | self._verified = True 617 | self.__raise( 618 | MethodCallError, 619 | '%s expected to be called %s times, called %s times' % 620 | (_format_args(self.name, self.args), message, self.times_called)) 621 | 622 | def _verify_number_of_calls(self, final): 623 | failed = False 624 | message = '' 625 | expected_calls = _getattr(self, 'expected_calls') 626 | times_called = _getattr(self, 'times_called') 627 | if expected_calls[EXACTLY] is not None: 628 | message = 'exactly %s' % expected_calls[EXACTLY] 629 | if final: 630 | if times_called != expected_calls[EXACTLY]: 631 | failed = True 632 | else: 633 | if times_called > expected_calls[EXACTLY]: 634 | failed = True 635 | else: 636 | if final and expected_calls[AT_LEAST] is not None: 637 | message = 'at least %s' % expected_calls[AT_LEAST] 638 | if times_called < expected_calls[AT_LEAST]: 639 | failed = True 640 | if expected_calls[AT_MOST] is not None: 641 | if message: 642 | message += ' and ' 643 | message += 'at most %s' % expected_calls[AT_MOST] 644 | if times_called > expected_calls[AT_MOST]: 645 | failed = True 646 | return failed, message 647 | 648 | def reset(self): 649 | """Returns the methods overriden by this expectation to their originals.""" 650 | _mock = _getattr(self, '_mock') 651 | if not isinstance(_mock, Mock): 652 | original = self.__dict__.get('original') 653 | if original: 654 | # name may be unicode but pypy demands dict keys to be str 655 | name = str(_getattr(self, 'name')) 656 | if (hasattr(_mock, '__dict__') and 657 | name in _mock.__dict__ and 658 | self._local_override): 659 | del _mock.__dict__[name] 660 | elif (hasattr(_mock, '__dict__') and 661 | name in _mock.__dict__ and 662 | type(_mock.__dict__) is dict): 663 | _mock.__dict__[name] = original 664 | else: 665 | setattr(_mock, name, original) 666 | del self 667 | 668 | 669 | class Mock(object): 670 | """Fake object class returned by the flexmock() function.""" 671 | 672 | def __init__(self, **kwargs): 673 | """Mock constructor. 674 | 675 | Args: 676 | - kwargs: dict of attribute/value pairs used to initialize the mock object 677 | """ 678 | self._object = self 679 | for attr, value in kwargs.items(): 680 | if type(value) is property: 681 | setattr(self.__class__, attr, value) 682 | else: 683 | setattr(self, attr, value) 684 | 685 | def __enter__(self): 686 | return self._object 687 | 688 | def __exit__(self, type, value, traceback): 689 | return self 690 | 691 | def __call__(self, *kargs, **kwargs): 692 | """Hack to make Expectation.mock() work with parens.""" 693 | return self 694 | 695 | def __iter__(self): 696 | """Makes the mock object iterable. 697 | 698 | Call the instance's version of __iter__ if available, otherwise yield self. 699 | """ 700 | if (hasattr(self, '__dict__') and type(self.__dict__) is dict and 701 | '__iter__' in self.__dict__): 702 | for item in self.__dict__['__iter__'](self): 703 | yield item 704 | else: 705 | yield self 706 | 707 | def should_receive(self, name): 708 | """Replaces the specified attribute with a fake. 709 | 710 | Args: 711 | - name: string name of the attribute to replace 712 | 713 | Returns: 714 | - Expectation object which can be used to modify the expectations 715 | on the fake attribute 716 | """ 717 | if name in UPDATED_ATTRS: 718 | raise FlexmockError('unable to replace flexmock methods') 719 | chained_methods = None 720 | obj = _getattr(self, '_object') 721 | if '.' in name: 722 | name, chained_methods = name.split('.', 1) 723 | name = _update_name_if_private(obj, name) 724 | _ensure_object_has_named_attribute(obj, name) 725 | if chained_methods: 726 | if (not isinstance(obj, Mock) and 727 | not hasattr(getattr(obj, name), '__call__')): 728 | return_value = _create_partial_mock(getattr(obj, name)) 729 | else: 730 | return_value = Mock() 731 | self._create_expectation(obj, name, return_value) 732 | return return_value.should_receive(chained_methods) 733 | else: 734 | return self._create_expectation(obj, name) 735 | 736 | def should_call(self, name): 737 | """Creates a spy. 738 | 739 | This means that the original method will be called rather than the fake 740 | version. However, we can still keep track of how many times it's called and 741 | with what arguments, and apply expectations accordingly. 742 | 743 | should_call is meaningless/not allowed for non-callable attributes. 744 | 745 | Args: 746 | - name: string name of the method 747 | 748 | Returns: 749 | - Expectation object 750 | """ 751 | expectation = self.should_receive(name) 752 | return expectation.replace_with(expectation.__dict__.get('original')) 753 | 754 | def new_instances(self, *kargs): 755 | """Overrides __new__ method on the class to return custom objects. 756 | 757 | Alias for should_receive('__new__').and_return(kargs).one_by_one 758 | 759 | Args: 760 | - kargs: objects to return on each successive call to __new__ 761 | 762 | Returns: 763 | - Expectation object 764 | """ 765 | if _isclass(self._object): 766 | return self.should_receive('__new__').and_return(kargs).one_by_one 767 | else: 768 | raise FlexmockError('new_instances can only be called on a class mock') 769 | 770 | def _create_expectation(self, obj, name, return_value=None): 771 | if self not in FlexmockContainer.flexmock_objects: 772 | FlexmockContainer.flexmock_objects[self] = [] 773 | expectation = self._save_expectation(name, return_value) 774 | FlexmockContainer.add_expectation(self, expectation) 775 | if _isproperty(obj, name): 776 | self._update_property(expectation, name, return_value) 777 | elif (isinstance(obj, Mock) or 778 | hasattr(getattr(obj, name), '__call__') or 779 | _isclass(getattr(obj, name))): 780 | self._update_method(expectation, name) 781 | else: 782 | self._update_attribute(expectation, name, return_value) 783 | return expectation 784 | 785 | def _save_expectation(self, name, return_value=None): 786 | if name in [x.name for x in 787 | FlexmockContainer.flexmock_objects[self]]: 788 | expectation = [x for x in FlexmockContainer.flexmock_objects[self] 789 | if x.name == name][0] 790 | expectation = Expectation( 791 | self._object, name=name, return_value=return_value, 792 | original=expectation.__dict__.get('original')) 793 | else: 794 | expectation = Expectation( 795 | self._object, name=name, return_value=return_value) 796 | return expectation 797 | 798 | def _update_class_for_magic_builtins( self, obj, name): 799 | """Fixes MRO for builtin methods on new-style objects. 800 | 801 | On 2.7+ and 3.2+, replacing magic builtins on instances of new-style 802 | classes has no effect as the one attached to the class takes precedence. 803 | To work around it, we update the class' method to check if the instance 804 | in question has one in its own __dict__ and call that instead. 805 | """ 806 | if not (name.startswith('__') and name.endswith('__') and len(name) > 4): 807 | return 808 | original = getattr(obj.__class__, name) 809 | def updated(self, *kargs, **kwargs): 810 | if (hasattr(self, '__dict__') and type(self.__dict__) is dict and 811 | name in self.__dict__): 812 | return self.__dict__[name](*kargs, **kwargs) 813 | else: 814 | return original(self, *kargs, **kwargs) 815 | setattr(obj.__class__, name, updated) 816 | if _get_code(updated) != _get_code(original): 817 | self._create_placeholder_mock_for_proper_teardown( 818 | obj.__class__, name, original) 819 | 820 | def _create_placeholder_mock_for_proper_teardown(self, obj, name, original): 821 | """Ensures that the given function is replaced on teardown.""" 822 | mock = Mock() 823 | mock._object = obj 824 | expectation = Expectation(obj, name=name, original=original) 825 | FlexmockContainer.add_expectation(mock, expectation) 826 | 827 | def _update_method(self, expectation, name): 828 | method_instance = self._create_mock_method(name) 829 | obj = self._object 830 | if _hasattr(obj, name) and not hasattr(expectation, 'original'): 831 | expectation._update_original(name, obj) 832 | method_type = type(_getattr(expectation, 'original')) 833 | try: 834 | # TODO(herman): this is awful, fix this properly. 835 | # When a class/static method is mocked out on an *instance* 836 | # we need to fetch the type from the class 837 | method_type = type(_getattr(obj.__class__, name)) 838 | except: pass 839 | if method_type in SPECIAL_METHODS: 840 | expectation.original_function = getattr(obj, name) 841 | expectation.method_type = method_type 842 | override = _setattr(obj, name, types.MethodType(method_instance, obj)) 843 | expectation._local_override = override 844 | if (override and not _isclass(obj) and not isinstance(obj, Mock) and 845 | hasattr(obj.__class__, name)): 846 | self._update_class_for_magic_builtins(obj, name) 847 | 848 | def _update_attribute(self, expectation, name, return_value=None): 849 | obj = self._object 850 | expectation._callable = False 851 | if _hasattr(obj, name) and not hasattr(expectation, 'original'): 852 | expectation._update_original(name, obj) 853 | override = _setattr(obj, name, return_value) 854 | expectation._local_override = override 855 | 856 | def _update_property(self, expectation, name, return_value=None): 857 | new_name = '_flexmock__%s' % name 858 | obj = self._object 859 | if not _isclass(obj): 860 | obj = obj.__class__ 861 | expectation._callable = False 862 | original = getattr(obj, name) 863 | @property 864 | def updated(self): 865 | if (hasattr(self, '__dict__') and type(self.__dict__) is dict and 866 | name in self.__dict__): 867 | return self.__dict__[name] 868 | else: 869 | return getattr(self, new_name) 870 | setattr(obj, name, updated) 871 | if not hasattr(obj, new_name): 872 | # don't try to double update 873 | FlexmockContainer.add_teardown_property(obj, new_name) 874 | setattr(obj, new_name, original) 875 | self._create_placeholder_mock_for_proper_teardown(obj, name, original) 876 | 877 | def _create_mock_method(self, name): 878 | def _handle_exception_matching(expectation): 879 | return_values = _getattr(expectation, 'return_values') 880 | if return_values: 881 | raised, instance = sys.exc_info()[:2] 882 | message = '%s' % instance 883 | expected = return_values[0].raises 884 | if not expected: 885 | raise 886 | args = return_values[0].value 887 | expected_instance = expected(*args['kargs'], **args['kwargs']) 888 | expected_message = '%s' % expected_instance 889 | if _isclass(expected): 890 | if expected is not raised and expected not in raised.__bases__: 891 | raise (ExceptionClassError('expected %s, raised %s' % 892 | (expected, raised))) 893 | if args['kargs'] and type(RE_TYPE) is type(args['kargs'][0]): 894 | if not args['kargs'][0].search(message): 895 | raise (ExceptionMessageError('expected /%s/, raised "%s"' % 896 | (args['kargs'][0].pattern, message))) 897 | elif expected_message and expected_message != message: 898 | raise (ExceptionMessageError('expected "%s", raised "%s"' % 899 | (expected_message, message))) 900 | elif expected is not raised: 901 | raise (ExceptionClassError('expected "%s", raised "%s"' % 902 | (expected, raised))) 903 | else: 904 | raise 905 | 906 | def match_return_values(expected, received): 907 | if not isinstance(expected, tuple): 908 | expected = (expected,) 909 | if not isinstance(received, tuple): 910 | received = (received,) 911 | if len(received) != len(expected): 912 | return False 913 | for i, val in enumerate(received): 914 | if not _arguments_match(val, expected[i]): 915 | return False 916 | return True 917 | 918 | def pass_thru(expectation, runtime_self, *kargs, **kwargs): 919 | return_values = None 920 | try: 921 | original = _getattr(expectation, 'original') 922 | _mock = _getattr(expectation, '_mock') 923 | if _isclass(_mock): 924 | if type(original) in SPECIAL_METHODS: 925 | original = _getattr(expectation, 'original_function') 926 | return_values = original(*kargs, **kwargs) 927 | else: 928 | return_values = original(runtime_self, *kargs, **kwargs) 929 | else: 930 | return_values = original(*kargs, **kwargs) 931 | except: 932 | return _handle_exception_matching(expectation) 933 | expected_values = _getattr(expectation, 'return_values') 934 | if (expected_values and 935 | not match_return_values(expected_values[0].value, return_values)): 936 | raise (MethodSignatureError('expected to return %s, returned %s' % 937 | (expected_values[0].value, return_values))) 938 | return return_values 939 | 940 | def mock_method(runtime_self, *kargs, **kwargs): 941 | arguments = {'kargs': kargs, 'kwargs': kwargs} 942 | expectation = FlexmockContainer.get_flexmock_expectation( 943 | self, name, arguments) 944 | if expectation: 945 | if not expectation.runnable(): 946 | raise StateError('%s expected to be called when %s is True' % 947 | (name, expectation._get_runnable())) 948 | expectation.times_called += 1 949 | expectation.verify(final=False) 950 | _pass_thru = _getattr(expectation, '_pass_thru') 951 | _replace_with = _getattr(expectation, '_replace_with') 952 | if _pass_thru: 953 | return pass_thru(expectation, runtime_self, *kargs, **kwargs) 954 | elif _replace_with: 955 | return _replace_with(*kargs, **kwargs) 956 | return_values = _getattr(expectation, 'return_values') 957 | if return_values: 958 | return_value = return_values[0] 959 | del return_values[0] 960 | return_values.append(return_value) 961 | else: 962 | return_value = ReturnValue() 963 | if return_value.raises: 964 | if _isclass(return_value.raises): 965 | raise return_value.raises( 966 | *return_value.value['kargs'], **return_value.value['kwargs']) 967 | else: 968 | raise return_value.raises 969 | else: 970 | return return_value.value 971 | else: 972 | # make sure to clean up expectations to ensure none of them 973 | # interfere with the runner's error reporing mechanism 974 | # e.g. open() 975 | for _, expectations in FlexmockContainer.flexmock_objects.items(): 976 | for expectation in expectations: 977 | _getattr(expectation, 'reset')() 978 | raise MethodSignatureError(_format_args(name, arguments)) 979 | 980 | return mock_method 981 | 982 | 983 | def _arg_to_str(arg): 984 | if type(RE_TYPE) is type(arg): 985 | return '/%s/' % arg.pattern 986 | if sys.version_info < (3, 0): 987 | # prior to 3.0 unicode strings are type unicode that inherits 988 | # from basestring along with str, in 3.0 both unicode and basestring 989 | # go away and str handles everything properly 990 | if isinstance(arg, basestring): 991 | return '"%s"' % (arg,) 992 | else: 993 | return '%s' % (arg,) 994 | else: 995 | if isinstance(arg, str): 996 | return '"%s"' % (arg,) 997 | else: 998 | return '%s' % (arg,) 999 | 1000 | 1001 | def _format_args(name, arguments): 1002 | if arguments is None: 1003 | arguments = {'kargs': (), 'kwargs': {}} 1004 | kargs = ', '.join(_arg_to_str(arg) for arg in arguments['kargs']) 1005 | kwargs = ', '.join('%s=%s' % (k, _arg_to_str(v)) for k, v in 1006 | arguments['kwargs'].items()) 1007 | if kargs and kwargs: 1008 | args = '%s, %s' % (kargs, kwargs) 1009 | else: 1010 | args = '%s%s' % (kargs, kwargs) 1011 | return '%s(%s)' % (name, args) 1012 | 1013 | 1014 | def _create_partial_mock(obj_or_class, **kwargs): 1015 | matches = [x for x in FlexmockContainer.flexmock_objects 1016 | if x._object is obj_or_class] 1017 | if matches: 1018 | mock = matches[0] 1019 | else: 1020 | mock = Mock() 1021 | mock._object = obj_or_class 1022 | for name, return_value in kwargs.items(): 1023 | if hasattr(return_value, '__call__'): 1024 | mock.should_receive(name).replace_with(return_value) 1025 | else: 1026 | mock.should_receive(name).and_return(return_value) 1027 | if not matches: 1028 | FlexmockContainer.add_expectation(mock, Expectation(obj_or_class)) 1029 | if (_attach_flexmock_methods(mock, Mock, obj_or_class) and 1030 | not _isclass(mock._object)): 1031 | mock = mock._object 1032 | return mock 1033 | 1034 | 1035 | def _attach_flexmock_methods(mock, flexmock_class, obj): 1036 | try: 1037 | for attr in UPDATED_ATTRS: 1038 | if hasattr(obj, attr): 1039 | if (_get_code(getattr(obj, attr)) is not 1040 | _get_code(getattr(flexmock_class, attr))): 1041 | return False 1042 | for attr in UPDATED_ATTRS: 1043 | _setattr(obj, attr, getattr(mock, attr)) 1044 | except TypeError: 1045 | raise MockBuiltinError( 1046 | 'Python does not allow you to mock builtin objects or modules. ' 1047 | 'Consider wrapping it in a class you can mock instead') 1048 | except AttributeError: 1049 | raise MockBuiltinError( 1050 | 'Python does not allow you to mock instances of builtin objects. ' 1051 | 'Consider wrapping it in a class you can mock instead') 1052 | return True 1053 | 1054 | 1055 | def _get_code(func): 1056 | if hasattr(func, 'func_code'): 1057 | code = 'func_code' 1058 | elif hasattr(func, 'im_func'): 1059 | func = func.im_func 1060 | code = 'func_code' 1061 | else: 1062 | code = '__code__' 1063 | return getattr(func, code) 1064 | 1065 | 1066 | def _arguments_match(arg, expected_arg): 1067 | if expected_arg == arg: 1068 | return True 1069 | elif _isclass(expected_arg) and isinstance(arg, expected_arg): 1070 | return True 1071 | elif (type(RE_TYPE) is type(expected_arg) and 1072 | expected_arg.search(arg)): 1073 | return True 1074 | else: 1075 | return False 1076 | 1077 | 1078 | def _getattr(obj, name): 1079 | """Convenience wrapper to work around custom __getattribute__.""" 1080 | return object.__getattribute__(obj, name) 1081 | 1082 | 1083 | def _setattr(obj, name, value): 1084 | """Ensure we use local __dict__ where possible.""" 1085 | name = str(name) # name may be unicode but pypy demands dict keys to be str 1086 | local_override = False 1087 | if hasattr(obj, '__dict__') and type(obj.__dict__) is dict: 1088 | if name not in obj.__dict__: 1089 | local_override = True 1090 | obj.__dict__[name] = value 1091 | else: 1092 | setattr(obj, name, value) 1093 | return local_override 1094 | 1095 | 1096 | def _hasattr(obj, name): 1097 | """Ensure hasattr checks don't create side-effects for properties.""" 1098 | if (not _isclass(obj) and hasattr(obj, '__dict__') and 1099 | name not in obj.__dict__): 1100 | if name in DEFAULT_CLASS_ATTRIBUTES: 1101 | return False # avoid false positives for things like __call__ 1102 | else: 1103 | return hasattr(obj.__class__, name) 1104 | else: 1105 | return hasattr(obj, name) 1106 | 1107 | 1108 | def _isclass(obj): 1109 | """Fixes stupid bug in inspect.isclass from < 2.7.""" 1110 | if sys.version_info < (2, 7): 1111 | return isinstance(obj, (type, types.ClassType)) 1112 | else: 1113 | return inspect.isclass(obj) 1114 | 1115 | 1116 | def _isproperty(obj, name): 1117 | if isinstance(obj, Mock): 1118 | return False 1119 | if not _isclass(obj) and hasattr(obj, '__dict__') and name not in obj.__dict__: 1120 | attr = getattr(obj.__class__, name) 1121 | if type(attr) is property: 1122 | return True 1123 | elif _isclass(obj): 1124 | attr = getattr(obj, name) 1125 | if type(attr) is property: 1126 | return True 1127 | return False 1128 | 1129 | 1130 | def _update_name_if_private(obj, name): 1131 | if (name.startswith('__') and not name.endswith('__') and 1132 | not inspect.ismodule(obj)): 1133 | if _isclass(obj): 1134 | class_name = obj.__name__ 1135 | else: 1136 | class_name = obj.__class__.__name__ 1137 | name = '_%s__%s' % (class_name.lstrip('_'), name.lstrip('_')) 1138 | return name 1139 | 1140 | 1141 | def _ensure_object_has_named_attribute(obj, name): 1142 | if not isinstance(obj, Mock) and not _hasattr(obj, name): 1143 | exc_msg = '%s does not have attribute %s' % (obj, name) 1144 | if name == '__new__': 1145 | exc_msg = 'old-style classes do not have a __new__() method' 1146 | raise FlexmockError(exc_msg) 1147 | 1148 | 1149 | def flexmock_teardown(): 1150 | """Performs lexmock-specific teardown tasks.""" 1151 | saved = {} 1152 | instances = [] 1153 | classes = [] 1154 | for mock_object, expectations in FlexmockContainer.flexmock_objects.items(): 1155 | saved[mock_object] = expectations[:] 1156 | for expectation in expectations: 1157 | _getattr(expectation, 'reset')() 1158 | for mock in saved.keys(): 1159 | obj = mock._object 1160 | if not isinstance(obj, Mock) and not _isclass(obj): 1161 | instances.append(obj) 1162 | if _isclass(obj): 1163 | classes.append(obj) 1164 | for obj in instances + classes: 1165 | for attr in UPDATED_ATTRS: 1166 | try: 1167 | obj_dict = obj.__dict__ 1168 | if _get_code(obj_dict[attr]) is _get_code(Mock.__dict__[attr]): 1169 | del obj_dict[attr] 1170 | except: 1171 | try: 1172 | if _get_code(getattr(obj, attr)) is _get_code(Mock.__dict__[attr]): 1173 | delattr(obj, attr) 1174 | except AttributeError: 1175 | pass 1176 | FlexmockContainer.teardown_properties() 1177 | FlexmockContainer.reset() 1178 | 1179 | # make sure this is done last to keep exceptions here from breaking 1180 | # any of the previous steps that cleanup all the changes 1181 | for mock_object, expectations in saved.items(): 1182 | for expectation in expectations: 1183 | _getattr(expectation, 'verify')() 1184 | 1185 | 1186 | def flexmock(spec=None, **kwargs): 1187 | """Main entry point into the flexmock API. 1188 | 1189 | This function is used to either generate a new fake object or take 1190 | an existing object (or class or module) and use it as a basis for 1191 | a partial mock. In case of a partial mock, the passed in object 1192 | is modified to support basic Mock class functionality making 1193 | it unnecessary to make successive flexmock() calls on the same 1194 | objects to generate new expectations. 1195 | 1196 | Examples: 1197 | >>> flexmock(SomeClass) 1198 | >>> SomeClass.should_receive('some_method') 1199 | 1200 | NOTE: it's safe to call flexmock() on the same object, it will detect 1201 | when an object has already been partially mocked and return it each time. 1202 | 1203 | Args: 1204 | - spec: object (or class or module) to mock 1205 | - kwargs: method/return_value pairs to attach to the object 1206 | 1207 | Returns: 1208 | Mock object if no spec is provided. Otherwise return the spec object. 1209 | """ 1210 | if spec is not None: 1211 | return _create_partial_mock(spec, **kwargs) 1212 | else: 1213 | # use this intermediate class to attach properties 1214 | klass = type('MockClass', (Mock,), {}) 1215 | return klass(**kwargs) 1216 | 1217 | 1218 | # RUNNER INTEGRATION 1219 | 1220 | 1221 | def _hook_into_pytest(): 1222 | try: 1223 | from _pytest import runner 1224 | saved = runner.call_runtest_hook 1225 | def call_runtest_hook(item, when, **kwargs): 1226 | ret = saved(item, when, **kwargs) 1227 | if when != 'call' and ret.excinfo is None: 1228 | return ret 1229 | teardown = runner.CallInfo(flexmock_teardown, when=when) 1230 | teardown.result = None 1231 | if ret.excinfo is not None and teardown.excinfo is None: 1232 | teardown.excinfo = ret.excinfo 1233 | return teardown 1234 | runner.call_runtest_hook = call_runtest_hook 1235 | 1236 | except ImportError: 1237 | pass 1238 | _hook_into_pytest() 1239 | 1240 | 1241 | def _hook_into_doctest(): 1242 | try: 1243 | from doctest import DocTestRunner 1244 | saved = DocTestRunner.run 1245 | def run(self, test, compileflags=None, out=None, clear_globs=True): 1246 | try: 1247 | return saved(self, test, compileflags, out, clear_globs) 1248 | finally: 1249 | flexmock_teardown() 1250 | DocTestRunner.run = run 1251 | except ImportError: 1252 | pass 1253 | _hook_into_doctest() 1254 | 1255 | 1256 | def _patch_test_result(klass): 1257 | """Patches flexmock into any class that inherits unittest.TestResult. 1258 | 1259 | This seems to work well for majority of test runners. In the case of nose 1260 | it's not even necessary as it doesn't override unittest.TestResults's 1261 | addSuccess and addFailure methods so simply patching unittest works 1262 | out of the box for nose. 1263 | 1264 | For those that do inherit from unittest.TestResult and override its 1265 | stopTest and addSuccess methods, patching is pretty straightforward 1266 | (numerous examples below). 1267 | 1268 | The reason we don't simply patch unittest's parent TestResult class 1269 | is stopTest and addSuccess in the child classes tend to add messages 1270 | into the output that we want to override in case flexmock generates 1271 | its own failures. 1272 | """ 1273 | 1274 | saved_addSuccess = klass.addSuccess 1275 | saved_stopTest = klass.stopTest 1276 | 1277 | def addSuccess(self, test): 1278 | self._pre_flexmock_success = True 1279 | 1280 | def stopTest(self, test): 1281 | if _get_code(saved_stopTest) is not _get_code(stopTest): 1282 | # if parent class was for some reason patched, avoid calling 1283 | # flexmock_teardown() twice and delegate up the class hierarchy 1284 | # this doesn't help if there is a gap and only the parent's 1285 | # parent class was patched, but should cover most screw-ups 1286 | try: 1287 | flexmock_teardown() 1288 | saved_addSuccess(self, test) 1289 | except: 1290 | if hasattr(self, '_pre_flexmock_success'): 1291 | self.addFailure(test, sys.exc_info()) 1292 | if hasattr(self, '_pre_flexmock_success'): 1293 | del self._pre_flexmock_success 1294 | return saved_stopTest(self, test) 1295 | 1296 | if klass.stopTest is not stopTest: 1297 | klass.stopTest = stopTest 1298 | 1299 | if klass.addSuccess is not addSuccess: 1300 | klass.addSuccess = addSuccess 1301 | 1302 | 1303 | def _hook_into_unittest(): 1304 | import unittest 1305 | try: 1306 | try: 1307 | # only valid TestResult class for unittest is TextTestResult 1308 | _patch_test_result(unittest.TextTestResult) 1309 | except AttributeError: 1310 | # ugh, python2.4 1311 | _patch_test_result(unittest._TextTestResult) 1312 | except: # let's not take any chances 1313 | pass 1314 | _hook_into_unittest() 1315 | 1316 | 1317 | def _hook_into_unittest2(): 1318 | try: 1319 | try: 1320 | from unittest2 import TextTestResult 1321 | except ImportError: 1322 | # Django has its own copy of unittest2 it uses as fallback 1323 | from django.utils.unittest import TextTestResult 1324 | _patch_test_result(TextTestResult) 1325 | except: 1326 | pass 1327 | _hook_into_unittest2() 1328 | 1329 | 1330 | def _hook_into_twisted(): 1331 | try: 1332 | from twisted.trial import reporter 1333 | _patch_test_result(reporter.MinimalReporter) 1334 | _patch_test_result(reporter.TextReporter) 1335 | _patch_test_result(reporter.VerboseTextReporter) 1336 | _patch_test_result(reporter.TreeReporter) 1337 | except: 1338 | pass 1339 | _hook_into_twisted() 1340 | 1341 | 1342 | def _hook_into_subunit(): 1343 | try: 1344 | import subunit 1345 | _patch_test_result(subunit.TestProtocolClient) 1346 | except: 1347 | pass 1348 | _hook_into_subunit() 1349 | 1350 | 1351 | def _hook_into_zope(): 1352 | try: 1353 | from zope import testrunner 1354 | _patch_test_result(testrunner.runner.TestResult) 1355 | except: 1356 | pass 1357 | _hook_into_zope() 1358 | 1359 | 1360 | def _hook_into_testtools(): 1361 | try: 1362 | from testtools import testresult 1363 | _patch_test_result(testresult.TestResult) 1364 | except: 1365 | pass 1366 | _hook_into_testtools() 1367 | 1368 | 1369 | def _hook_into_teamcity_unittest(): 1370 | try: 1371 | from tcunittest import TeamcityTestResult 1372 | _patch_test_result(TeamcityTestResult) 1373 | except: 1374 | pass 1375 | _hook_into_teamcity_unittest() 1376 | 1377 | # Dark magic to make the flexmock module itself callable. 1378 | # So that you can say: 1379 | # import flexmock 1380 | # instead of: 1381 | # from flexmock import flexmock 1382 | class _CallableModule(types.ModuleType): 1383 | def __init__(self): 1384 | super(_CallableModule, self).__init__('flexmock') 1385 | self._realmod = sys.modules['flexmock'] 1386 | sys.modules['flexmock'] = self 1387 | self.__doc__ = flexmock.__doc__ 1388 | def __dir__(self): 1389 | return dir(self._realmod) 1390 | def __call__(self, *args, **kw): 1391 | return self._realmod.flexmock(*args, **kw) 1392 | def __getattr__(self, attr): 1393 | return getattr(self._realmod, attr) 1394 | 1395 | _CallableModule() 1396 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | from setuptools import setup 3 | except ImportError: 4 | from distutils.core import setup 5 | 6 | setup(name='flexmock', 7 | version='0.9.7', 8 | py_modules=['flexmock'], 9 | author='Slavek Kabrda, Herman Sheremetyev', 10 | author_email='slavek@redhat.com', 11 | url='http://flexmock.readthedocs.org', 12 | license='FreeBSD style license', 13 | ) 14 | -------------------------------------------------------------------------------- /tests/flexmock_modern_test.py: -------------------------------------------------------------------------------- 1 | import flexmock 2 | import sys 3 | import unittest 4 | 5 | class ModernClass(object): 6 | """Contains features only available in 2.6 and above.""" 7 | def test_context_manager_on_instance(self): 8 | class CM(object): 9 | def __enter__(self): pass 10 | def __exit__(self, *_): pass 11 | cm = CM() 12 | flexmock(cm).should_call('__enter__').once 13 | flexmock(cm).should_call('__exit__').once 14 | with cm: pass 15 | self._tear_down() 16 | 17 | def test_context_manager_on_class(self): 18 | class CM(object): 19 | def __enter__(self): pass 20 | def __exit__(self, *_): pass 21 | cm = CM() 22 | flexmock(CM).should_receive('__enter__').once 23 | flexmock(CM).should_receive('__exit__').once 24 | with cm: pass 25 | self._tear_down() 26 | 27 | def test_flexmock_should_support_with(self): 28 | foo = flexmock() 29 | with foo as mock: 30 | mock.should_receive('bar').and_return('baz') 31 | assert foo.bar() == 'baz' 32 | 33 | def test_builtin_open(self): 34 | if sys.version_info < (3, 0): 35 | mock = flexmock(sys.modules['__builtin__']) 36 | else: 37 | mock = flexmock(sys.modules['builtins']) 38 | fake_fd = flexmock(read=lambda: 'some data') 39 | mock.should_receive('open').once.with_args('file_name').and_return(fake_fd) 40 | with open('file_name') as f: 41 | data = f.read() 42 | self.assertEqual('some data', data) 43 | 44 | 45 | 46 | class TestFlexmockUnittestModern(ModernClass, unittest.TestCase): 47 | def _tear_down(self): 48 | return unittest.TestCase.tearDown(self) 49 | 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /tests/flexmock_nose_test.py: -------------------------------------------------------------------------------- 1 | from flexmock import MethodCallError 2 | from flexmock import flexmock_teardown 3 | from flexmock_test import assertRaises 4 | from nose import with_setup 5 | import flexmock 6 | import flexmock_test 7 | import unittest 8 | 9 | 10 | def test_module_level(): 11 | m = flexmock(mod=2) 12 | m.should_receive('mod').once 13 | assertRaises(MethodCallError, flexmock_teardown) 14 | 15 | 16 | def test_module_level_generator(): 17 | mock = flexmock(foo=lambda x, y: None, bar=lambda: None) 18 | mock.should_receive('bar').never # change never to once to observe the failure 19 | for i in range(0, 3): 20 | yield mock.foo, i, i*3 21 | 22 | 23 | class TestRegularClass(flexmock_test.RegularClass): 24 | 25 | def test_regular(self): 26 | a = flexmock(a=2) 27 | a.should_receive('a').once 28 | assertRaises(MethodCallError, flexmock_teardown) 29 | 30 | def test_class_level_generator_tests(self): 31 | mock = flexmock(foo=lambda a, b: a) 32 | mock.should_receive('bar').never # change never to once to observe the failure 33 | for i in range(0, 3): 34 | yield mock.foo, i, i*3 35 | 36 | 37 | class TestUnittestClass(flexmock_test.TestFlexmockUnittest): 38 | 39 | def test_unittest(self): 40 | a = flexmock(a=2) 41 | a.should_receive('a').once 42 | assertRaises(MethodCallError, flexmock_teardown) 43 | -------------------------------------------------------------------------------- /tests/flexmock_pytest_test.py: -------------------------------------------------------------------------------- 1 | from flexmock import MethodCallError 2 | from flexmock import flexmock_teardown 3 | from flexmock_test import assertRaises 4 | import flexmock 5 | import flexmock_test 6 | import unittest 7 | import pytest 8 | 9 | 10 | def test_module_level_test_for_pytest(): 11 | flexmock(foo='bar').should_receive('foo').once 12 | assertRaises(MethodCallError, flexmock_teardown) 13 | 14 | 15 | @pytest.fixture() 16 | def runtest_hook_fixture(): 17 | return flexmock(foo='bar').should_receive('foo').once.mock() 18 | 19 | def test_runtest_hook_with_fixture_for_pytest(runtest_hook_fixture): 20 | runtest_hook_fixture.foo() 21 | 22 | 23 | class TestForPytest(flexmock_test.RegularClass): 24 | 25 | def test_class_level_test_for_pytest(self): 26 | flexmock(foo='bar').should_receive('foo').once 27 | assertRaises(MethodCallError, flexmock_teardown) 28 | 29 | 30 | class TestUnittestClass(flexmock_test.TestFlexmockUnittest): 31 | 32 | def test_unittest(self): 33 | a = flexmock(a=2) 34 | a.should_receive('a').once 35 | assertRaises(MethodCallError, flexmock_teardown) 36 | 37 | 38 | class TestFailureOnException(object): 39 | 40 | @pytest.mark.xfail(raises=RuntimeError) 41 | def test_exception(self): 42 | raise RuntimeError("TEST ERROR") 43 | 44 | -------------------------------------------------------------------------------- /tests/flexmock_test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | from flexmock import EXACTLY 3 | from flexmock import AT_LEAST 4 | from flexmock import AT_MOST 5 | from flexmock import UPDATED_ATTRS 6 | from flexmock import Mock 7 | from flexmock import MockBuiltinError 8 | from flexmock import FlexmockContainer 9 | from flexmock import FlexmockError 10 | from flexmock import MethodSignatureError 11 | from flexmock import ExceptionClassError 12 | from flexmock import ExceptionMessageError 13 | from flexmock import StateError 14 | from flexmock import MethodCallError 15 | from flexmock import CallOrderError 16 | from flexmock import ReturnValue 17 | from flexmock import flexmock_teardown 18 | from flexmock import _format_args 19 | from flexmock import _isproperty 20 | import flexmock 21 | import re 22 | import sys 23 | import unittest 24 | 25 | 26 | def module_level_function(some, args): 27 | return "%s, %s" % (some, args) 28 | 29 | 30 | module_level_attribute = 'test' 31 | 32 | 33 | class OldStyleClass: 34 | pass 35 | 36 | 37 | class NewStyleClass(object): 38 | pass 39 | 40 | 41 | def assertRaises(exception, method, *kargs, **kwargs): 42 | try: 43 | method(*kargs, **kwargs) 44 | except exception: 45 | return 46 | except: 47 | instance = sys.exc_info()[1] 48 | print('%s' % instance) 49 | raise Exception('%s not raised' % exception.__name__) 50 | 51 | 52 | def assertEqual(expected, received, msg=''): 53 | if not msg: 54 | msg = 'expected %s, received %s' % (expected, received) 55 | if expected != received: 56 | raise AssertionError('%s != %s : %s' % (expected, received, msg)) 57 | 58 | 59 | class RegularClass(object): 60 | 61 | def _tear_down(self): 62 | return flexmock_teardown() 63 | 64 | def test_flexmock_should_create_mock_object(self): 65 | mock = flexmock() 66 | assert isinstance(mock, Mock) 67 | 68 | def test_flexmock_should_create_mock_object_from_dict(self): 69 | mock = flexmock(foo='foo', bar='bar') 70 | assertEqual('foo', mock.foo) 71 | assertEqual('bar', mock.bar) 72 | 73 | def test_flexmock_should_add_expectations(self): 74 | mock = flexmock(name='temp') 75 | mock.should_receive('method_foo') 76 | assert ('method_foo' in 77 | [x.name for x in FlexmockContainer.flexmock_objects[mock]]) 78 | 79 | def test_flexmock_should_return_value(self): 80 | mock = flexmock(name='temp') 81 | mock.should_receive('method_foo').and_return('value_bar') 82 | mock.should_receive('method_bar').and_return('value_baz') 83 | assertEqual('value_bar', mock.method_foo()) 84 | assertEqual('value_baz', mock.method_bar()) 85 | 86 | def test_type_flexmock_with_unicode_string_in_should_receive(self): 87 | class Foo(object): 88 | def bar(self): return 'bar' 89 | 90 | flexmock(Foo).should_receive(u'bar').and_return('mocked_bar') 91 | 92 | foo = Foo() 93 | assertEqual('mocked_bar', foo.bar()) 94 | 95 | def test_flexmock_should_accept_shortcuts_for_creating_mock_object(self): 96 | mock = flexmock(attr1='value 1', attr2=lambda: 'returning 2') 97 | assertEqual('value 1', mock.attr1) 98 | assertEqual('returning 2', mock.attr2()) 99 | 100 | def test_flexmock_should_accept_shortcuts_for_creating_expectations(self): 101 | class Foo: 102 | def method1(self): pass 103 | def method2(self): pass 104 | foo = Foo() 105 | flexmock(foo, method1='returning 1', method2='returning 2') 106 | assertEqual('returning 1', foo.method1()) 107 | assertEqual('returning 2', foo.method2()) 108 | assertEqual('returning 2', foo.method2()) 109 | 110 | def test_flexmock_expectations_returns_all(self): 111 | mock = flexmock(name='temp') 112 | assert mock not in FlexmockContainer.flexmock_objects 113 | mock.should_receive('method_foo') 114 | mock.should_receive('method_bar') 115 | assertEqual(2, len(FlexmockContainer.flexmock_objects[mock])) 116 | 117 | def test_flexmock_expectations_returns_named_expectation(self): 118 | mock = flexmock(name='temp') 119 | mock.should_receive('method_foo') 120 | assertEqual('method_foo', 121 | FlexmockContainer.get_flexmock_expectation( 122 | mock, 'method_foo').name) 123 | 124 | def test_flexmock_expectations_returns_none_if_not_found(self): 125 | mock = flexmock(name='temp') 126 | mock.should_receive('method_foo') 127 | assert (FlexmockContainer.get_flexmock_expectation( 128 | mock, 'method_bar') is None) 129 | 130 | def test_flexmock_should_check_parameters(self): 131 | mock = flexmock(name='temp') 132 | mock.should_receive('method_foo').with_args('bar').and_return(1) 133 | mock.should_receive('method_foo').with_args('baz').and_return(2) 134 | assertEqual(1, mock.method_foo('bar')) 135 | assertEqual(2, mock.method_foo('baz')) 136 | 137 | def test_flexmock_should_keep_track_of_calls(self): 138 | mock = flexmock(name='temp') 139 | mock.should_receive('method_foo').with_args('foo').and_return(0) 140 | mock.should_receive('method_foo').with_args('bar').and_return(1) 141 | mock.should_receive('method_foo').with_args('baz').and_return(2) 142 | mock.method_foo('bar') 143 | mock.method_foo('bar') 144 | mock.method_foo('baz') 145 | expectation = FlexmockContainer.get_flexmock_expectation( 146 | mock, 'method_foo', ('foo',)) 147 | assertEqual(0, expectation.times_called) 148 | expectation = FlexmockContainer.get_flexmock_expectation( 149 | mock, 'method_foo', ('bar',)) 150 | assertEqual(2, expectation.times_called) 151 | expectation = FlexmockContainer.get_flexmock_expectation( 152 | mock, 'method_foo', ('baz',)) 153 | assertEqual(1, expectation.times_called) 154 | 155 | def test_flexmock_should_set_expectation_call_numbers(self): 156 | mock = flexmock(name='temp') 157 | mock.should_receive('method_foo').times(1) 158 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 159 | assertRaises(MethodCallError, expectation.verify) 160 | mock.method_foo() 161 | expectation.verify() 162 | 163 | def test_flexmock_should_check_raised_exceptions(self): 164 | mock = flexmock(name='temp') 165 | class FakeException(Exception): 166 | pass 167 | mock.should_receive('method_foo').and_raise(FakeException) 168 | assertRaises(FakeException, mock.method_foo) 169 | assertEqual(1, 170 | FlexmockContainer.get_flexmock_expectation( 171 | mock, 'method_foo').times_called) 172 | 173 | def test_flexmock_should_check_raised_exceptions_instance_with_args(self): 174 | mock = flexmock(name='temp') 175 | class FakeException(Exception): 176 | def __init__(self, arg, arg2): 177 | pass 178 | mock.should_receive('method_foo').and_raise(FakeException(1, arg2=2)) 179 | assertRaises(FakeException, mock.method_foo) 180 | assertEqual(1, 181 | FlexmockContainer.get_flexmock_expectation( 182 | mock, 'method_foo').times_called) 183 | 184 | def test_flexmock_should_check_raised_exceptions_class_with_args(self): 185 | mock = flexmock(name='temp') 186 | class FakeException(Exception): 187 | def __init__(self, arg, arg2): 188 | pass 189 | mock.should_receive('method_foo').and_raise(FakeException, 1, arg2=2) 190 | assertRaises(FakeException, mock.method_foo) 191 | assertEqual(1, 192 | FlexmockContainer.get_flexmock_expectation( 193 | mock, 'method_foo').times_called) 194 | 195 | def test_flexmock_should_match_any_args_by_default(self): 196 | mock = flexmock(name='temp') 197 | mock.should_receive('method_foo').and_return('bar') 198 | mock.should_receive('method_foo').with_args('baz').and_return('baz') 199 | assertEqual('bar', mock.method_foo()) 200 | assertEqual('bar', mock.method_foo(1)) 201 | assertEqual('bar', mock.method_foo('foo', 'bar')) 202 | assertEqual('baz', mock.method_foo('baz')) 203 | 204 | def test_flexmock_should_fail_to_match_exactly_no_args_when_calling_with_args(self): 205 | mock = flexmock() 206 | mock.should_receive('method_foo').with_args() 207 | assertRaises(MethodSignatureError, mock.method_foo, 'baz') 208 | 209 | def test_flexmock_should_match_exactly_no_args(self): 210 | class Foo: 211 | def bar(self): pass 212 | foo = Foo() 213 | flexmock(foo).should_receive('bar').with_args().and_return('baz') 214 | assertEqual('baz', foo.bar()) 215 | 216 | def test_expectation_dot_mock_should_return_mock(self): 217 | mock = flexmock(name='temp') 218 | assertEqual(mock, mock.should_receive('method_foo').mock) 219 | 220 | def test_flexmock_should_create_partial_new_style_object_mock(self): 221 | class User(object): 222 | def __init__(self, name=None): 223 | self.name = name 224 | def get_name(self): 225 | return self.name 226 | def set_name(self, name): 227 | self.name = name 228 | user = User() 229 | flexmock(user) 230 | user.should_receive('get_name').and_return('john') 231 | user.set_name('mike') 232 | assertEqual('john', user.get_name()) 233 | 234 | def test_flexmock_should_create_partial_old_style_object_mock(self): 235 | class User: 236 | def __init__(self, name=None): 237 | self.name = name 238 | def get_name(self): 239 | return self.name 240 | def set_name(self, name): 241 | self.name = name 242 | user = User() 243 | flexmock(user) 244 | user.should_receive('get_name').and_return('john') 245 | user.set_name('mike') 246 | assertEqual('john', user.get_name()) 247 | 248 | def test_flexmock_should_create_partial_new_style_class_mock(self): 249 | class User(object): 250 | def __init__(self): pass 251 | def get_name(self): pass 252 | flexmock(User) 253 | User.should_receive('get_name').and_return('mike') 254 | user = User() 255 | assertEqual('mike', user.get_name()) 256 | 257 | def test_flexmock_should_create_partial_old_style_class_mock(self): 258 | class User: 259 | def __init__(self): pass 260 | def get_name(self): pass 261 | flexmock(User) 262 | User.should_receive('get_name').and_return('mike') 263 | user = User() 264 | assertEqual('mike', user.get_name()) 265 | 266 | def test_flexmock_should_match_expectations_against_builtin_classes(self): 267 | mock = flexmock(name='temp') 268 | mock.should_receive('method_foo').with_args(str).and_return('got a string') 269 | mock.should_receive('method_foo').with_args(int).and_return('got an int') 270 | assertEqual('got a string', mock.method_foo('string!')) 271 | assertEqual('got an int', mock.method_foo(23)) 272 | assertRaises(MethodSignatureError, mock.method_foo, 2.0) 273 | 274 | def test_flexmock_should_match_expectations_against_user_defined_classes(self): 275 | mock = flexmock(name='temp') 276 | class Foo: 277 | pass 278 | mock.should_receive('method_foo').with_args(Foo).and_return('got a Foo') 279 | assertEqual('got a Foo', mock.method_foo(Foo())) 280 | assertRaises(MethodSignatureError, mock.method_foo, 1) 281 | 282 | def test_flexmock_configures_global_mocks_dict(self): 283 | mock = flexmock(name='temp') 284 | assert mock not in FlexmockContainer.flexmock_objects 285 | mock.should_receive('method_foo') 286 | assert mock in FlexmockContainer.flexmock_objects 287 | assertEqual(len(FlexmockContainer.flexmock_objects[mock]), 1) 288 | 289 | def test_flexmock_teardown_verifies_mocks(self): 290 | mock = flexmock(name='temp') 291 | mock.should_receive('verify_expectations').times(1) 292 | assertRaises(MethodCallError, self._tear_down) 293 | 294 | def test_flexmock_teardown_does_not_verify_stubs(self): 295 | mock = flexmock(name='temp') 296 | mock.should_receive('verify_expectations') 297 | self._tear_down() 298 | 299 | def test_flexmock_preserves_stubbed_object_methods_between_tests(self): 300 | class User: 301 | def get_name(self): 302 | return 'mike' 303 | user = User() 304 | flexmock(user).should_receive('get_name').and_return('john') 305 | assertEqual('john', user.get_name()) 306 | self._tear_down() 307 | assertEqual('mike', user.get_name()) 308 | 309 | def test_flexmock_preserves_stubbed_class_methods_between_tests(self): 310 | class User: 311 | def get_name(self): 312 | return 'mike' 313 | user = User() 314 | flexmock(User).should_receive('get_name').and_return('john') 315 | assertEqual('john', user.get_name()) 316 | self._tear_down() 317 | assertEqual('mike', user.get_name()) 318 | 319 | def test_flexmock_removes_new_stubs_from_objects_after_tests(self): 320 | class User: 321 | def get_name(self): pass 322 | user = User() 323 | saved = user.get_name 324 | flexmock(user).should_receive('get_name').and_return('john') 325 | assert saved != user.get_name 326 | assertEqual('john', user.get_name()) 327 | self._tear_down() 328 | assertEqual(saved, user.get_name) 329 | 330 | def test_flexmock_removes_new_stubs_from_classes_after_tests(self): 331 | class User: 332 | def get_name(self): pass 333 | user = User() 334 | saved = user.get_name 335 | flexmock(User).should_receive('get_name').and_return('john') 336 | assert saved != user.get_name 337 | assertEqual('john', user.get_name()) 338 | self._tear_down() 339 | assertEqual(saved, user.get_name) 340 | 341 | def test_flexmock_removes_stubs_from_multiple_objects_on_teardown(self): 342 | class User: 343 | def get_name(self): pass 344 | class Group: 345 | def get_name(self): pass 346 | user = User() 347 | group = User() 348 | saved1 = user.get_name 349 | saved2 = group.get_name 350 | flexmock(user).should_receive('get_name').and_return('john').once() 351 | flexmock(group).should_receive('get_name').and_return('john').once() 352 | assert saved1 != user.get_name 353 | assert saved2 != group.get_name 354 | assertEqual('john', user.get_name()) 355 | assertEqual('john', group.get_name()) 356 | self._tear_down() 357 | assertEqual(saved1, user.get_name) 358 | assertEqual(saved2, group.get_name) 359 | 360 | def test_flexmock_removes_stubs_from_multiple_classes_on_teardown(self): 361 | class User: 362 | def get_name(self): pass 363 | class Group: 364 | def get_name(self): pass 365 | user = User() 366 | group = User() 367 | saved1 = user.get_name 368 | saved2 = group.get_name 369 | flexmock(User).should_receive('get_name').and_return('john') 370 | flexmock(Group).should_receive('get_name').and_return('john') 371 | assert saved1 != user.get_name 372 | assert saved2 != group.get_name 373 | assertEqual('john', user.get_name()) 374 | assertEqual('john', group.get_name()) 375 | self._tear_down() 376 | assertEqual(saved1, user.get_name) 377 | assertEqual(saved2, group.get_name) 378 | 379 | def test_flexmock_respects_at_least_when_called_less_than_requested(self): 380 | mock = flexmock(name='temp') 381 | mock.should_receive('method_foo').and_return('bar').at_least().twice() 382 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 383 | assertEqual(AT_LEAST, expectation.modifier) 384 | mock.method_foo() 385 | assertRaises(MethodCallError, self._tear_down) 386 | 387 | def test_flexmock_respects_at_least_when_called_requested_number(self): 388 | mock = flexmock(name='temp') 389 | mock.should_receive('method_foo').and_return('value_bar').at_least().once() 390 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 391 | assertEqual(AT_LEAST, expectation.modifier) 392 | mock.method_foo() 393 | self._tear_down() 394 | 395 | def test_flexmock_respects_at_least_when_called_more_than_requested(self): 396 | mock = flexmock(name='temp') 397 | mock.should_receive('method_foo').and_return('value_bar').at_least().once() 398 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 399 | assertEqual(AT_LEAST, expectation.modifier) 400 | mock.method_foo() 401 | mock.method_foo() 402 | self._tear_down() 403 | 404 | def test_flexmock_respects_at_most_when_called_less_than_requested(self): 405 | mock = flexmock(name='temp') 406 | mock.should_receive('method_foo').and_return('bar').at_most().twice() 407 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 408 | assertEqual(AT_MOST, expectation.modifier) 409 | mock.method_foo() 410 | self._tear_down() 411 | 412 | def test_flexmock_respects_at_most_when_called_requested_number(self): 413 | mock = flexmock(name='temp') 414 | mock.should_receive('method_foo').and_return('value_bar').at_most().once() 415 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 416 | assertEqual(AT_MOST, expectation.modifier) 417 | mock.method_foo() 418 | self._tear_down() 419 | 420 | def test_flexmock_respects_at_most_when_called_more_than_requested(self): 421 | mock = flexmock(name='temp') 422 | mock.should_receive('method_foo').and_return('value_bar').at_most().once() 423 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 424 | assertEqual(AT_MOST, expectation.modifier) 425 | mock.method_foo() 426 | assertRaises(MethodCallError, mock.method_foo) 427 | 428 | def test_flexmock_treats_once_as_times_one(self): 429 | mock = flexmock(name='temp') 430 | mock.should_receive('method_foo').and_return('value_bar').once() 431 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 432 | assertEqual(1, expectation.expected_calls[EXACTLY]) 433 | assertRaises(MethodCallError, self._tear_down) 434 | 435 | def test_flexmock_treats_twice_as_times_two(self): 436 | mock = flexmock(name='temp') 437 | mock.should_receive('method_foo').twice().and_return('value_bar') 438 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 439 | assertEqual(2, expectation.expected_calls[EXACTLY]) 440 | assertRaises(MethodCallError, self._tear_down) 441 | 442 | def test_flexmock_works_with_never_when_true(self): 443 | mock = flexmock(name='temp') 444 | mock.should_receive('method_foo').and_return('value_bar').never 445 | expectation = FlexmockContainer.get_flexmock_expectation(mock, 'method_foo') 446 | assertEqual(0, expectation.expected_calls[EXACTLY]) 447 | self._tear_down() 448 | 449 | def test_flexmock_works_with_never_when_false(self): 450 | mock = flexmock(name='temp') 451 | mock.should_receive('method_foo').and_return('value_bar').never 452 | assertRaises(MethodCallError, mock.method_foo) 453 | 454 | def test_flexmock_get_flexmock_expectation_should_work_with_args(self): 455 | mock = flexmock(name='temp') 456 | mock.should_receive('method_foo').with_args('value_bar') 457 | assert FlexmockContainer.get_flexmock_expectation( 458 | mock, 'method_foo', 'value_bar') 459 | 460 | def test_flexmock_function_should_return_previously_mocked_object(self): 461 | class User(object): pass 462 | user = User() 463 | foo = flexmock(user) 464 | assert foo == user 465 | assert foo == flexmock(user) 466 | 467 | def test_flexmock_should_not_return_class_object_if_mocking_instance(self): 468 | class User: 469 | def method(self): pass 470 | user = User() 471 | user2 = User() 472 | class_mock = flexmock(User).should_receive( 473 | 'method').and_return('class').mock 474 | user_mock = flexmock(user).should_receive( 475 | 'method').and_return('instance').mock 476 | assert class_mock is not user_mock 477 | assertEqual('instance', user.method()) 478 | assertEqual('class', user2.method()) 479 | 480 | def test_should_call_on_class_mock(self): 481 | class User: 482 | def foo(self): return 'class' 483 | user1 = User() 484 | user2 = User() 485 | flexmock(User).should_call('foo').once() 486 | assertRaises(MethodCallError, self._tear_down) 487 | flexmock(User).should_call('foo').twice() 488 | assertEqual('class', user1.foo()) 489 | assertEqual('class', user2.foo()) 490 | 491 | def test_flexmock_should_not_blow_up_on_should_call_for_class_methods(self): 492 | class User: 493 | @classmethod 494 | def foo(self): 495 | return 'class' 496 | flexmock(User).should_call('foo') 497 | assertEqual('class', User.foo()) 498 | 499 | def test_flexmock_should_not_blow_up_on_should_call_for_static_methods(self): 500 | class User: 501 | @staticmethod 502 | def foo(): 503 | return 'static' 504 | flexmock(User).should_call('foo') 505 | assertEqual('static', User.foo()) 506 | 507 | def test_flexmock_should_mock_new_instances_with_multiple_params(self): 508 | class User(object): pass 509 | class Group(object): 510 | def __init__(self, arg, arg2): 511 | pass 512 | user = User() 513 | flexmock(Group).new_instances(user) 514 | assert user is Group(1, 2) 515 | 516 | def test_flexmock_should_revert_new_instances_on_teardown(self): 517 | class User(object): pass 518 | class Group(object): pass 519 | user = User() 520 | group = Group() 521 | flexmock(Group).new_instances(user) 522 | assert user is Group() 523 | self._tear_down() 524 | assertEqual(group.__class__, Group().__class__) 525 | 526 | def test_flexmock_should_cleanup_added_methods_and_attributes(self): 527 | class Group(object): pass 528 | group = Group() 529 | flexmock(Group) 530 | assert 'should_receive' in Group.__dict__ 531 | assert 'should_receive' not in group.__dict__ 532 | flexmock(group) 533 | assert 'should_receive' in group.__dict__ 534 | self._tear_down() 535 | for method in UPDATED_ATTRS: 536 | assert method not in Group.__dict__ 537 | assert method not in group.__dict__ 538 | 539 | def test_flexmock_should_cleanup_after_exception(self): 540 | class User: 541 | def method2(self): pass 542 | class Group: 543 | def method1(self): pass 544 | flexmock(Group) 545 | flexmock(User) 546 | Group.should_receive('method1').once() 547 | User.should_receive('method2').once() 548 | assertRaises(MethodCallError, self._tear_down) 549 | for method in UPDATED_ATTRS: 550 | assert method not in dir(Group) 551 | for method in UPDATED_ATTRS: 552 | assert method not in dir(User) 553 | 554 | def test_flexmock_should_call_respects_matched_expectations(self): 555 | class Group(object): 556 | def method1(self, arg1, arg2='b'): 557 | return '%s:%s' % (arg1, arg2) 558 | def method2(self, arg): 559 | return arg 560 | group = Group() 561 | flexmock(group).should_call('method1').twice() 562 | assertEqual('a:c', group.method1('a', arg2='c')) 563 | assertEqual('a:b', group.method1('a')) 564 | group.should_call('method2').once().with_args('c') 565 | assertEqual('c', group.method2('c')) 566 | self._tear_down() 567 | 568 | def test_flexmock_should_call_respects_unmatched_expectations(self): 569 | class Group(object): 570 | def method1(self, arg1, arg2='b'): 571 | return '%s:%s' % (arg1, arg2) 572 | def method2(self, a): pass 573 | group = Group() 574 | flexmock(group).should_call('method1').at_least().once() 575 | assertRaises(MethodCallError, self._tear_down) 576 | flexmock(group) 577 | group.should_call('method2').with_args('a').once() 578 | group.should_receive('method2').with_args('not a') 579 | group.method2('not a') 580 | assertRaises(MethodCallError, self._tear_down) 581 | 582 | def test_flexmock_doesnt_error_on_properly_ordered_expectations(self): 583 | class Foo(object): 584 | def foo(self): pass 585 | def method1(self, a): pass 586 | def bar(self): pass 587 | def baz(self): pass 588 | foo = Foo() 589 | flexmock(foo).should_receive('foo') 590 | flexmock(foo).should_receive('method1').with_args('a').ordered() 591 | flexmock(foo).should_receive('bar') 592 | flexmock(foo).should_receive('method1').with_args('b').ordered() 593 | flexmock(foo).should_receive('baz') 594 | foo.bar() 595 | foo.method1('a') 596 | foo.method1('b') 597 | foo.baz() 598 | foo.foo() 599 | 600 | def test_flexmock_errors_on_improperly_ordered_expectations(self): 601 | class Foo(object): 602 | def method1(self, a): pass 603 | foo = Foo() 604 | flexmock(foo) 605 | foo.should_receive('method1').with_args('a').ordered() 606 | foo.should_receive('method1').with_args('b').ordered() 607 | assertRaises(CallOrderError, foo.method1, 'b') 608 | 609 | def test_flexmock_should_accept_multiple_return_values(self): 610 | class Foo: 611 | def method1(self): pass 612 | foo = Foo() 613 | flexmock(foo).should_receive('method1').and_return(1, 5).and_return(2) 614 | assertEqual((1, 5), foo.method1()) 615 | assertEqual(2, foo.method1()) 616 | assertEqual((1, 5), foo.method1()) 617 | assertEqual(2, foo.method1()) 618 | 619 | def test_flexmock_should_accept_multiple_return_values_with_shortcut(self): 620 | class Foo: 621 | def method1(self): pass 622 | foo = Foo() 623 | flexmock(foo).should_receive('method1').and_return(1, 2).one_by_one() 624 | assertEqual(1, foo.method1()) 625 | assertEqual(2, foo.method1()) 626 | assertEqual(1, foo.method1()) 627 | assertEqual(2, foo.method1()) 628 | 629 | def test_flexmock_should_mix_multiple_return_values_with_exceptions(self): 630 | class Foo: 631 | def method1(self): pass 632 | foo = Foo() 633 | flexmock(foo).should_receive('method1').and_return(1).and_raise(Exception) 634 | assertEqual(1, foo.method1()) 635 | assertRaises(Exception, foo.method1) 636 | assertEqual(1, foo.method1()) 637 | assertRaises(Exception, foo.method1) 638 | 639 | def test_flexmock_should_match_types_on_multiple_arguments(self): 640 | class Foo: 641 | def method1(self, a, b): pass 642 | foo = Foo() 643 | flexmock(foo).should_receive('method1').with_args(str, int).and_return('ok') 644 | assertEqual('ok', foo.method1('some string', 12)) 645 | assertRaises(MethodSignatureError, foo.method1, 12, 32) 646 | flexmock(foo).should_receive('method1').with_args(str, int).and_return('ok') 647 | assertRaises(MethodSignatureError, foo.method1, 12, 'some string') 648 | flexmock(foo).should_receive('method1').with_args(str, int).and_return('ok') 649 | assertRaises(MethodSignatureError, foo.method1, 'string', 12, 14) 650 | 651 | def test_flexmock_should_match_types_on_multiple_arguments_generic(self): 652 | class Foo: 653 | def method1(self, a, b, c): pass 654 | foo = Foo() 655 | flexmock(foo).should_receive('method1').with_args( 656 | object, object, object).and_return('ok') 657 | assertEqual('ok', foo.method1('some string', None, 12)) 658 | assertEqual('ok', foo.method1((1,), None, 12)) 659 | assertEqual('ok', foo.method1(12, 14, [])) 660 | assertEqual('ok', foo.method1('some string', 'another one', False)) 661 | assertRaises(MethodSignatureError, foo.method1, 'string', 12) 662 | flexmock(foo).should_receive('method1').with_args( 663 | object, object, object).and_return('ok') 664 | assertRaises(MethodSignatureError, foo.method1, 'string', 12, 13, 14) 665 | 666 | def test_flexmock_should_match_types_on_multiple_arguments_classes(self): 667 | class Foo: 668 | def method1(self, a, b): pass 669 | class Bar: pass 670 | foo = Foo() 671 | bar = Bar() 672 | flexmock(foo).should_receive('method1').with_args( 673 | object, Bar).and_return('ok') 674 | assertEqual('ok', foo.method1('some string', bar)) 675 | assertRaises(MethodSignatureError, foo.method1, bar, 'some string') 676 | flexmock(foo).should_receive('method1').with_args( 677 | object, Bar).and_return('ok') 678 | assertRaises(MethodSignatureError, foo.method1, 12, 'some string') 679 | 680 | def test_flexmock_should_match_keyword_arguments(self): 681 | class Foo: 682 | def method1(self, a, **kwargs): pass 683 | foo = Foo() 684 | flexmock(foo).should_receive('method1').with_args(1, arg3=3, arg2=2).twice() 685 | foo.method1(1, arg2=2, arg3=3) 686 | foo.method1(1, arg3=3, arg2=2) 687 | self._tear_down() 688 | flexmock(foo).should_receive('method1').with_args(1, arg3=3, arg2=2) 689 | assertRaises(MethodSignatureError, foo.method1, arg2=2, arg3=3) 690 | flexmock(foo).should_receive('method1').with_args(1, arg3=3, arg2=2) 691 | assertRaises(MethodSignatureError, foo.method1, 1, arg2=2, arg3=4) 692 | flexmock(foo).should_receive('method1').with_args(1, arg3=3, arg2=2) 693 | assertRaises(MethodSignatureError, foo.method1, 1) 694 | 695 | def test_flexmock_should_call_should_match_keyword_arguments(self): 696 | class Foo: 697 | def method1(self, arg1, arg2=None, arg3=None): 698 | return '%s%s%s' % (arg1, arg2, arg3) 699 | foo = Foo() 700 | flexmock(foo).should_call('method1').with_args(1, arg3=3, arg2=2).once() 701 | assertEqual('123', foo.method1(1, arg2=2, arg3=3)) 702 | 703 | def test_flexmock_should_mock_private_methods(self): 704 | class Foo: 705 | def __private_method(self): 706 | return 'foo' 707 | def public_method(self): 708 | return self.__private_method() 709 | foo = Foo() 710 | flexmock(foo).should_receive('__private_method').and_return('bar') 711 | assertEqual('bar', foo.public_method()) 712 | 713 | def test_flexmock_should_mock_special_methods(self): 714 | class Foo: 715 | def __special_method__(self): 716 | return 'foo' 717 | def public_method(self): 718 | return self.__special_method__() 719 | foo = Foo() 720 | flexmock(foo).should_receive('__special_method__').and_return('bar') 721 | assertEqual('bar', foo.public_method()) 722 | 723 | def test_flexmock_should_mock_double_underscore_method(self): 724 | class Foo: 725 | def __(self): 726 | return 'foo' 727 | def public_method(self): 728 | return self.__() 729 | foo = Foo() 730 | flexmock(foo).should_receive('__').and_return('bar') 731 | assertEqual('bar', foo.public_method()) 732 | 733 | def test_flexmock_should_mock_private_class_methods(self): 734 | class Foo: 735 | def __iter__(self): pass 736 | flexmock(Foo).should_receive('__iter__').and_yield(1, 2, 3) 737 | assertEqual([1, 2, 3], [x for x in Foo()]) 738 | 739 | def test_flexmock_should_mock_iter_on_new_style_instances(self): 740 | class Foo(object): 741 | def __iter__(self): 742 | yield None 743 | old = Foo.__iter__ 744 | foo = Foo() 745 | foo2 = Foo() 746 | foo3 = Foo() 747 | flexmock(foo, __iter__=iter([1, 2, 3])) 748 | flexmock(foo2, __iter__=iter([3, 4, 5])) 749 | assertEqual([1, 2, 3], [x for x in foo]) 750 | assertEqual([3, 4, 5], [x for x in foo2]) 751 | assertEqual([None], [x for x in foo3]) 752 | assertEqual(False, foo.__iter__ == old) 753 | assertEqual(False, foo2.__iter__ == old) 754 | assertEqual(False, foo3.__iter__ == old) 755 | self._tear_down() 756 | assertEqual([None], [x for x in foo]) 757 | assertEqual([None], [x for x in foo2]) 758 | assertEqual([None], [x for x in foo3]) 759 | assertEqual(True, Foo.__iter__ == old, '%s != %s' % (Foo.__iter__, old)) 760 | 761 | def test_flexmock_should_mock_private_methods_with_leading_underscores(self): 762 | class _Foo: 763 | def __stuff(self): pass 764 | def public_method(self): 765 | return self.__stuff() 766 | foo = _Foo() 767 | flexmock(foo).should_receive('__stuff').and_return('bar') 768 | assertEqual('bar', foo.public_method()) 769 | 770 | def test_flexmock_should_mock_generators(self): 771 | class Gen: 772 | def foo(self): pass 773 | gen = Gen() 774 | flexmock(gen).should_receive('foo').and_yield(*range(1, 10)) 775 | output = [val for val in gen.foo()] 776 | assertEqual([val for val in range(1, 10)], output) 777 | 778 | def test_flexmock_should_verify_correct_spy_return_values(self): 779 | class User: 780 | def get_stuff(self): return 'real', 'stuff' 781 | user = User() 782 | flexmock(user).should_call('get_stuff').and_return('real', 'stuff') 783 | assertEqual(('real', 'stuff'), user.get_stuff()) 784 | 785 | def test_flexmock_should_verify_correct_spy_regexp_return_values(self): 786 | class User: 787 | def get_stuff(self): return 'real', 'stuff' 788 | user = User() 789 | flexmock(user).should_call('get_stuff').and_return( 790 | re.compile('ea.*'), re.compile('^stuff$')) 791 | assertEqual(('real', 'stuff'), user.get_stuff()) 792 | 793 | def test_flexmock_should_verify_spy_raises_correct_exception_class(self): 794 | class FakeException(Exception): 795 | def __init__(self, param, param2): 796 | self.message = '%s, %s' % (param, param2) 797 | Exception.__init__(self) 798 | class User: 799 | def get_stuff(self): raise FakeException(1, 2) 800 | user = User() 801 | flexmock(user).should_call('get_stuff').and_raise(FakeException, 1, 2) 802 | user.get_stuff() 803 | 804 | def test_flexmock_should_verify_spy_matches_exception_message(self): 805 | class FakeException(Exception): 806 | def __init__(self, param, param2): 807 | self.p1 = param 808 | self.p2 = param2 809 | Exception.__init__(self, param) 810 | def __str__(self): 811 | return '%s, %s' % (self.p1, self.p2) 812 | class User: 813 | def get_stuff(self): raise FakeException('1', '2') 814 | user = User() 815 | flexmock(user).should_call('get_stuff').and_raise(FakeException, '2', '1') 816 | assertRaises(ExceptionMessageError, user.get_stuff) 817 | 818 | def test_flexmock_should_verify_spy_matches_exception_regexp(self): 819 | class User: 820 | def get_stuff(self): raise Exception('123asdf345') 821 | user = User() 822 | flexmock(user).should_call( 823 | 'get_stuff').and_raise(Exception, re.compile('asdf')) 824 | user.get_stuff() 825 | self._tear_down() 826 | 827 | def test_flexmock_should_verify_spy_matches_exception_regexp_mismatch(self): 828 | class User: 829 | def get_stuff(self): raise Exception('123asdf345') 830 | user = User() 831 | flexmock(user).should_call( 832 | 'get_stuff').and_raise(Exception, re.compile('^asdf')) 833 | assertRaises(ExceptionMessageError, user.get_stuff) 834 | 835 | def test_flexmock_should_blow_up_on_wrong_spy_exception_type(self): 836 | class User: 837 | def get_stuff(self): raise CallOrderError('foo') 838 | user = User() 839 | flexmock(user).should_call('get_stuff').and_raise(MethodCallError) 840 | assertRaises(ExceptionClassError, user.get_stuff) 841 | 842 | def test_flexmock_should_match_spy_exception_parent_type(self): 843 | class User: 844 | def get_stuff(self): raise CallOrderError('foo') 845 | user = User() 846 | flexmock(user).should_call('get_stuff').and_raise(FlexmockError) 847 | user.get_stuff() 848 | 849 | def test_flexmock_should_blow_up_on_wrong_spy_return_values(self): 850 | class User: 851 | def get_stuff(self): return 'real', 'stuff' 852 | def get_more_stuff(self): return 'other', 'stuff' 853 | user = User() 854 | flexmock(user).should_call('get_stuff').and_return('other', 'stuff') 855 | assertRaises(MethodSignatureError, user.get_stuff) 856 | flexmock(user).should_call('get_more_stuff').and_return() 857 | assertRaises(MethodSignatureError, user.get_more_stuff) 858 | 859 | def test_flexmock_should_mock_same_class_twice(self): 860 | class Foo: pass 861 | flexmock(Foo) 862 | flexmock(Foo) 863 | 864 | def test_flexmock_spy_should_not_clobber_original_method(self): 865 | class User: 866 | def get_stuff(self): return 'real', 'stuff' 867 | user = User() 868 | flexmock(user).should_call('get_stuff') 869 | flexmock(user).should_call('get_stuff') 870 | assertEqual(('real', 'stuff'), user.get_stuff()) 871 | 872 | def test_flexmock_should_properly_restore_static_methods(self): 873 | class User: 874 | @staticmethod 875 | def get_stuff(): return 'ok!' 876 | assertEqual('ok!', User.get_stuff()) 877 | flexmock(User).should_receive('get_stuff') 878 | assert User.get_stuff() is None 879 | self._tear_down() 880 | assertEqual('ok!', User.get_stuff()) 881 | 882 | def test_flexmock_should_properly_restore_undecorated_static_methods(self): 883 | class User: 884 | def get_stuff(): return 'ok!' 885 | get_stuff = staticmethod(get_stuff) 886 | assertEqual('ok!', User.get_stuff()) 887 | flexmock(User).should_receive('get_stuff') 888 | assert User.get_stuff() is None 889 | self._tear_down() 890 | assertEqual('ok!', User.get_stuff()) 891 | 892 | def test_flexmock_should_properly_restore_module_level_functions(self): 893 | if 'flexmock_test' in sys.modules: 894 | mod = sys.modules['flexmock_test'] 895 | else: 896 | mod = sys.modules['__main__'] 897 | flexmock(mod).should_receive('module_level_function').with_args(1, 2) 898 | assertEqual(None, module_level_function(1, 2)) 899 | self._tear_down() 900 | assertEqual('1, 2', module_level_function(1, 2)) 901 | 902 | def test_module_level_function_with_kwargs(self): 903 | if 'flexmock_test' in sys.modules: 904 | mod = sys.modules['flexmock_test'] 905 | else: 906 | mod = sys.modules['__main__'] 907 | flexmock(mod).should_receive('module_level_function').with_args( 908 | 1, args="expected") 909 | assertRaises(FlexmockError, module_level_function, 1, args="not expected") 910 | 911 | def test_flexmock_should_support_mocking_old_style_classes_as_functions(self): 912 | if 'flexmock_test' in sys.modules: 913 | mod = sys.modules['flexmock_test'] 914 | else: 915 | mod = sys.modules['__main__'] 916 | flexmock(mod).should_receive('OldStyleClass').and_return('yay') 917 | assertEqual('yay', OldStyleClass()) 918 | 919 | def test_flexmock_should_support_mocking_new_style_classes_as_functions(self): 920 | if 'flexmock_test' in sys.modules: 921 | mod = sys.modules['flexmock_test'] 922 | else: 923 | mod = sys.modules['__main__'] 924 | flexmock(mod).should_receive('NewStyleClass').and_return('yay') 925 | assertEqual('yay', NewStyleClass()) 926 | 927 | def test_flexmock_should_properly_restore_class_methods(self): 928 | class User: 929 | @classmethod 930 | def get_stuff(cls): 931 | return cls.__name__ 932 | assertEqual('User', User.get_stuff()) 933 | flexmock(User).should_receive('get_stuff').and_return('foo') 934 | assertEqual('foo', User.get_stuff()) 935 | self._tear_down() 936 | assertEqual('User', User.get_stuff()) 937 | 938 | def test_spy_should_match_return_value_class(self): 939 | class User: pass 940 | user = User() 941 | foo = flexmock(foo=lambda: ('bar', 'baz'), 942 | bar=lambda: user, 943 | baz=lambda: None, 944 | bax=lambda: None) 945 | foo.should_call('foo').and_return(str, str) 946 | foo.should_call('bar').and_return(User) 947 | foo.should_call('baz').and_return(object) 948 | foo.should_call('bax').and_return(None) 949 | assertEqual(('bar', 'baz'), foo.foo()) 950 | assertEqual(user, foo.bar()) 951 | assertEqual(None, foo.baz()) 952 | assertEqual(None, foo.bax()) 953 | 954 | def test_spy_should_not_match_falsy_stuff(self): 955 | class Foo: 956 | def foo(self): return None 957 | def bar(self): return False 958 | def baz(self): return [] 959 | def quux(self): return '' 960 | foo = Foo() 961 | flexmock(foo).should_call('foo').and_return('bar').once 962 | flexmock(foo).should_call('bar').and_return('bar').once 963 | flexmock(foo).should_call('baz').and_return('bar').once 964 | flexmock(foo).should_call('quux').and_return('bar').once 965 | assertRaises(FlexmockError, foo.foo) 966 | assertRaises(FlexmockError, foo.bar) 967 | assertRaises(FlexmockError, foo.baz) 968 | assertRaises(FlexmockError, foo.quux) 969 | 970 | def test_new_instances_should_blow_up_on_should_receive(self): 971 | class User(object): pass 972 | mock = flexmock(User).new_instances(None).mock 973 | assertRaises(FlexmockError, mock.should_receive, 'foo') 974 | 975 | def test_should_call_alias_should_create_a_spy(self): 976 | class Foo: 977 | def get_stuff(self): 978 | return 'yay' 979 | foo = Foo() 980 | flexmock(foo).should_call('get_stuff').and_return('yay').once() 981 | assertRaises(MethodCallError, self._tear_down) 982 | 983 | def test_flexmock_should_fail_mocking_nonexistent_methods(self): 984 | class User: pass 985 | user = User() 986 | assertRaises(FlexmockError, 987 | flexmock(user).should_receive, 'nonexistent') 988 | 989 | def test_flexmock_should_not_explode_on_unicode_formatting(self): 990 | if sys.version_info >= (3, 0): 991 | formatted = _format_args( 992 | 'method', {'kargs' : (chr(0x86C7),), 'kwargs' : {}}) 993 | assertEqual('method("蛇")', formatted) 994 | else: 995 | formatted = _format_args( 996 | 'method', {'kargs' : (unichr(0x86C7),), 'kwargs' : {}}) 997 | assertEqual('method("%s")' % unichr(0x86C7), formatted) 998 | 999 | def test_return_value_should_not_explode_on_unicode_values(self): 1000 | class Foo: 1001 | def method(self): pass 1002 | if sys.version_info >= (3, 0): 1003 | return_value = ReturnValue(chr(0x86C7)) 1004 | assertEqual('"蛇"', '%s' % return_value) 1005 | return_value = ReturnValue((chr(0x86C7), chr(0x86C7))) 1006 | assertEqual('("蛇", "蛇")', '%s' % return_value) 1007 | else: 1008 | return_value = ReturnValue(unichr(0x86C7)) 1009 | assertEqual('"%s"' % unichr(0x86C7), unicode(return_value)) 1010 | 1011 | def test_pass_thru_should_call_original_method_only_once(self): 1012 | class Nyan(object): 1013 | def __init__(self): 1014 | self.n = 0 1015 | def method(self): 1016 | self.n += 1 1017 | obj = Nyan() 1018 | flexmock(obj) 1019 | obj.should_call('method') 1020 | obj.method() 1021 | assertEqual(obj.n, 1) 1022 | 1023 | def test_should_call_works_for_same_method_with_different_args(self): 1024 | class Foo: 1025 | def method(self, arg): 1026 | pass 1027 | foo = Foo() 1028 | flexmock(foo).should_call('method').with_args('foo').once() 1029 | flexmock(foo).should_call('method').with_args('bar').once() 1030 | foo.method('foo') 1031 | foo.method('bar') 1032 | self._tear_down() 1033 | 1034 | def test_should_call_fails_properly_for_same_method_with_different_args(self): 1035 | class Foo: 1036 | def method(self, arg): 1037 | pass 1038 | foo = Foo() 1039 | flexmock(foo).should_call('method').with_args('foo').once() 1040 | flexmock(foo).should_call('method').with_args('bar').once() 1041 | foo.method('foo') 1042 | assertRaises(MethodCallError, self._tear_down) 1043 | 1044 | def test_should_give_reasonable_error_for_builtins(self): 1045 | assertRaises(MockBuiltinError, flexmock, object) 1046 | 1047 | def test_should_give_reasonable_error_for_instances_of_builtins(self): 1048 | assertRaises(MockBuiltinError, flexmock, object()) 1049 | 1050 | def test_mock_chained_method_calls_works_with_one_level(self): 1051 | class Foo: 1052 | def method2(self): 1053 | return 'foo' 1054 | class Bar: 1055 | def method1(self): 1056 | return Foo() 1057 | foo = Bar() 1058 | assertEqual('foo', foo.method1().method2()) 1059 | flexmock(foo).should_receive('method1.method2').and_return('bar') 1060 | assertEqual('bar', foo.method1().method2()) 1061 | 1062 | def test_mock_chained_method_supports_args_and_mocks(self): 1063 | class Foo: 1064 | def method2(self, arg): 1065 | return arg 1066 | class Bar: 1067 | def method1(self): 1068 | return Foo() 1069 | foo = Bar() 1070 | assertEqual('foo', foo.method1().method2('foo')) 1071 | flexmock(foo).should_receive('method1.method2').with_args( 1072 | 'foo').and_return('bar').once() 1073 | assertEqual('bar', foo.method1().method2('foo')) 1074 | self._tear_down() 1075 | flexmock(foo).should_receive('method1.method2').with_args( 1076 | 'foo').and_return('bar').once() 1077 | assertRaises(MethodCallError, self._tear_down) 1078 | 1079 | def test_mock_chained_method_calls_works_with_more_than_one_level(self): 1080 | class Baz: 1081 | def method3(self): 1082 | return 'foo' 1083 | class Foo: 1084 | def method2(self): 1085 | return Baz() 1086 | class Bar: 1087 | def method1(self): 1088 | return Foo() 1089 | foo = Bar() 1090 | assertEqual('foo', foo.method1().method2().method3()) 1091 | flexmock(foo).should_receive('method1.method2.method3').and_return('bar') 1092 | assertEqual('bar', foo.method1().method2().method3()) 1093 | 1094 | def test_flexmock_should_replace_method(self): 1095 | class Foo: 1096 | def method(self, arg): 1097 | return arg 1098 | foo = Foo() 1099 | flexmock(foo).should_receive('method').replace_with(lambda x: x == 5) 1100 | assertEqual(foo.method(5), True) 1101 | assertEqual(foo.method(4), False) 1102 | 1103 | def test_flexmock_should_replace_cannot_be_specified_twice(self): 1104 | class Foo: 1105 | def method(self, arg): 1106 | return arg 1107 | foo = Foo() 1108 | expectation = flexmock(foo).should_receive( 1109 | 'method').replace_with(lambda x: x == 5) 1110 | assertRaises(FlexmockError, 1111 | expectation.replace_with, lambda x: x == 3) 1112 | 1113 | def test_flexmock_should_mock_the_same_method_multiple_times(self): 1114 | class Foo: 1115 | def method(self): pass 1116 | foo = Foo() 1117 | flexmock(foo).should_receive('method').and_return(1) 1118 | assertEqual(foo.method(), 1) 1119 | flexmock(foo).should_receive('method').and_return(2) 1120 | assertEqual(foo.method(), 2) 1121 | flexmock(foo).should_receive('method').and_return(3) 1122 | assertEqual(foo.method(), 3) 1123 | flexmock(foo).should_receive('method').and_return(4) 1124 | assertEqual(foo.method(), 4) 1125 | 1126 | def test_new_instances_should_be_a_method(self): 1127 | class Foo(object): pass 1128 | flexmock(Foo).new_instances('bar') 1129 | assertEqual('bar', Foo()) 1130 | self._tear_down() 1131 | assert 'bar' != Foo() 1132 | 1133 | def test_new_instances_raises_error_when_not_a_class(self): 1134 | class Foo(object): pass 1135 | foo = Foo() 1136 | flexmock(foo) 1137 | assertRaises(FlexmockError, foo.new_instances, 'bar') 1138 | 1139 | def test_new_instances_works_with_multiple_return_values(self): 1140 | class Foo(object): pass 1141 | flexmock(Foo).new_instances('foo', 'bar') 1142 | assertEqual('foo', Foo()) 1143 | assertEqual('bar', Foo()) 1144 | 1145 | def test_should_receive_should_not_replace_flexmock_methods(self): 1146 | class Foo: 1147 | def bar(self): pass 1148 | foo = Foo() 1149 | flexmock(foo) 1150 | assertRaises(FlexmockError, foo.should_receive, 'should_receive') 1151 | 1152 | def test_flexmock_should_not_add_methods_if_they_already_exist(self): 1153 | class Foo: 1154 | def should_receive(self): 1155 | return 'real' 1156 | def bar(self): pass 1157 | foo = Foo() 1158 | mock = flexmock(foo) 1159 | assertEqual(foo.should_receive(), 'real') 1160 | assert 'should_call' not in dir(foo) 1161 | assert 'new_instances' not in dir(foo) 1162 | mock.should_receive('bar').and_return('baz') 1163 | assertEqual(foo.bar(), 'baz') 1164 | self._tear_down() 1165 | assertEqual(foo.should_receive(), 'real') 1166 | 1167 | def test_flexmock_should_not_add_class_methods_if_they_already_exist(self): 1168 | class Foo: 1169 | def should_receive(self): 1170 | return 'real' 1171 | def bar(self): pass 1172 | foo = Foo() 1173 | mock = flexmock(Foo) 1174 | assertEqual(foo.should_receive(), 'real') 1175 | assert 'should_call' not in dir(Foo) 1176 | assert 'new_instances' not in dir(Foo) 1177 | mock.should_receive('bar').and_return('baz') 1178 | assertEqual(foo.bar(), 'baz') 1179 | self._tear_down() 1180 | assertEqual(foo.should_receive(), 'real') 1181 | 1182 | def test_expectation_properties_work_with_parens(self): 1183 | foo = flexmock().should_receive( 1184 | 'bar').at_least().once().and_return('baz').mock() 1185 | assertEqual('baz', foo.bar()) 1186 | 1187 | def test_mocking_down_the_inheritance_chain_class_to_class(self): 1188 | class Parent(object): 1189 | def foo(self): pass 1190 | class Child(Parent): 1191 | def bar(self): pass 1192 | 1193 | flexmock(Parent).should_receive('foo').and_return('outer') 1194 | flexmock(Child).should_receive('bar').and_return('inner') 1195 | assert 'outer', Parent().foo() 1196 | assert 'inner', Child().bar() 1197 | 1198 | def test_arg_matching_works_with_regexp(self): 1199 | class Foo: 1200 | def foo(self, arg1, arg2): pass 1201 | foo = Foo() 1202 | flexmock(foo).should_receive('foo').with_args( 1203 | re.compile('^arg1.*asdf$'), arg2=re.compile('f')).and_return('mocked') 1204 | assertEqual('mocked', foo.foo('arg1somejunkasdf', arg2='aadsfdas')) 1205 | 1206 | def test_arg_matching_with_regexp_fails_when_regexp_doesnt_match_karg(self): 1207 | class Foo: 1208 | def foo(self, arg1, arg2): pass 1209 | foo = Foo() 1210 | flexmock(foo).should_receive('foo').with_args( 1211 | re.compile('^arg1.*asdf$'), arg2=re.compile('a')).and_return('mocked') 1212 | assertRaises(MethodSignatureError, foo.foo, 'arg1somejunkasdfa', arg2='a') 1213 | 1214 | def test_arg_matching_with_regexp_fails_when_regexp_doesnt_match_kwarg(self): 1215 | class Foo: 1216 | def foo(self, arg1, arg2): pass 1217 | foo = Foo() 1218 | flexmock(foo).should_receive('foo').with_args( 1219 | re.compile('^arg1.*asdf$'), arg2=re.compile('a')).and_return('mocked') 1220 | assertRaises(MethodSignatureError, foo.foo, 'arg1somejunkasdf', arg2='b') 1221 | 1222 | def test_flexmock_class_returns_same_object_on_repeated_calls(self): 1223 | class Foo: pass 1224 | a = flexmock(Foo) 1225 | b = flexmock(Foo) 1226 | assertEqual(a, b) 1227 | 1228 | def test_flexmock_object_returns_same_object_on_repeated_calls(self): 1229 | class Foo: pass 1230 | foo = Foo() 1231 | a = flexmock(foo) 1232 | b = flexmock(foo) 1233 | assertEqual(a, b) 1234 | 1235 | def test_flexmock_ordered_worked_after_default_stub(self): 1236 | foo = flexmock() 1237 | foo.should_receive('bar') 1238 | foo.should_receive('bar').with_args('a').ordered() 1239 | foo.should_receive('bar').with_args('b').ordered() 1240 | assertRaises(CallOrderError, foo.bar, 'b') 1241 | 1242 | def test_flexmock_ordered_works_with_same_args(self): 1243 | foo = flexmock() 1244 | foo.should_receive('bar').ordered().and_return(1) 1245 | foo.should_receive('bar').ordered().and_return(2) 1246 | a = foo.bar() 1247 | assertEqual(a, 1) 1248 | b = foo.bar() 1249 | assertEqual(b, 2) 1250 | 1251 | def test_flexmock_ordered_works_with_same_args_after_default_stub(self): 1252 | foo = flexmock() 1253 | foo.should_receive('bar').and_return(9) 1254 | foo.should_receive('bar').ordered().and_return(1) 1255 | foo.should_receive('bar').ordered().and_return(2) 1256 | a = foo.bar() 1257 | assertEqual(a, 1) 1258 | b = foo.bar() 1259 | assertEqual(b, 2) 1260 | c = foo.bar() 1261 | assertEqual(c, 9) 1262 | 1263 | def test_state_machine(self): 1264 | class Radio: 1265 | def __init__(self): self.is_on = False 1266 | def switch_on(self): self.is_on = True 1267 | def switch_off(self): self.is_on = False 1268 | def select_channel(self): return None 1269 | def adjust_volume(self, num): self.volume = num 1270 | 1271 | radio = Radio() 1272 | flexmock(radio) 1273 | radio.should_receive('select_channel').once().when( 1274 | lambda: radio.is_on) 1275 | radio.should_call('adjust_volume').once().with_args(5).when( 1276 | lambda: radio.is_on) 1277 | 1278 | assertRaises(StateError, radio.select_channel) 1279 | assertRaises(StateError, radio.adjust_volume, 5) 1280 | radio.is_on = True 1281 | radio.select_channel() 1282 | radio.adjust_volume(5) 1283 | 1284 | def test_support_at_least_and_at_most_together(self): 1285 | class Foo: 1286 | def bar(self): pass 1287 | 1288 | foo = Foo() 1289 | flexmock(foo).should_call('bar').at_least().once().at_most().twice() 1290 | assertRaises(MethodCallError, self._tear_down) 1291 | 1292 | flexmock(foo).should_call('bar').at_least().once().at_most().twice() 1293 | foo.bar() 1294 | foo.bar() 1295 | assertRaises(MethodCallError, foo.bar) 1296 | 1297 | flexmock(foo).should_call('bar').at_least().once().at_most().twice() 1298 | foo.bar() 1299 | self._tear_down() 1300 | 1301 | flexmock(foo).should_call('bar').at_least().once().at_most().twice() 1302 | foo.bar() 1303 | foo.bar() 1304 | self._tear_down() 1305 | 1306 | def test_at_least_cannot_be_used_twice(self): 1307 | class Foo: 1308 | def bar(self): pass 1309 | 1310 | expectation = flexmock(Foo).should_receive('bar') 1311 | try: 1312 | expectation.at_least().at_least() 1313 | raise Exception('should not be able to specify at_least twice') 1314 | except FlexmockError: 1315 | pass 1316 | except Exception: 1317 | raise 1318 | 1319 | def test_at_most_cannot_be_used_twice(self): 1320 | class Foo: 1321 | def bar(self): pass 1322 | 1323 | expectation = flexmock(Foo).should_receive('bar') 1324 | try: 1325 | expectation.at_most().at_most() 1326 | raise Exception('should not be able to specify at_most twice') 1327 | except FlexmockError: 1328 | pass 1329 | except Exception: 1330 | raise 1331 | 1332 | def test_at_least_cannot_be_specified_until_at_most_is_set(self): 1333 | class Foo: 1334 | def bar(self): pass 1335 | 1336 | expectation = flexmock(Foo).should_receive('bar') 1337 | try: 1338 | expectation.at_least().at_most() 1339 | raise Exception('should not be able to specify at_most if at_least unset') 1340 | except FlexmockError: 1341 | pass 1342 | except Exception: 1343 | raise 1344 | 1345 | def test_at_most_cannot_be_specified_until_at_least_is_set(self): 1346 | class Foo: 1347 | def bar(self): pass 1348 | 1349 | expectation = flexmock(Foo).should_receive('bar') 1350 | try: 1351 | expectation.at_most().at_least() 1352 | raise Exception('should not be able to specify at_least if at_most unset') 1353 | except FlexmockError: 1354 | pass 1355 | except Exception: 1356 | raise 1357 | 1358 | def test_proper_reset_of_subclass_methods(self): 1359 | class A: 1360 | def x(self): 1361 | return 'a' 1362 | class B(A): 1363 | def x(self): 1364 | return 'b' 1365 | flexmock(B).should_receive('x').and_return('1') 1366 | self._tear_down() 1367 | assertEqual('b', B().x()) 1368 | 1369 | def test_format_args_supports_tuples(self): 1370 | formatted = _format_args('method', {'kargs' : ((1, 2),), 'kwargs' : {}}) 1371 | assertEqual('method((1, 2))', formatted) 1372 | 1373 | def test_mocking_subclass_of_str(self): 1374 | class String(str): pass 1375 | s = String() 1376 | flexmock(s, endswith='fake') 1377 | assertEqual('fake', s.endswith('stuff')) 1378 | self._tear_down() 1379 | assertEqual(False, s.endswith('stuff')) 1380 | 1381 | def test_ordered_on_different_methods(self): 1382 | class String(str): pass 1383 | s = String('abc') 1384 | flexmock(s) 1385 | s.should_call('startswith').with_args('asdf', 0, 4).ordered() 1386 | s.should_call('endswith').ordered() 1387 | assertRaises(CallOrderError, s.endswith, 'c') 1388 | 1389 | def test_fake_object_takes_properties(self): 1390 | foo = flexmock(bar=property(lambda self: 'baz')) 1391 | bar = flexmock(foo=property(lambda self: 'baz')) 1392 | assertEqual('baz', foo.bar) 1393 | assertEqual('baz', bar.foo) 1394 | 1395 | def test_replace_non_callable_class_attributes(self): 1396 | class Foo: 1397 | bar = 1 1398 | foo = Foo() 1399 | bar = Foo() 1400 | flexmock(foo, bar=2) 1401 | assertEqual(2, foo.bar) 1402 | assertEqual(1, bar.bar) 1403 | self._tear_down() 1404 | assertEqual(1, foo.bar) 1405 | 1406 | def test_should_chain_attributes(self): 1407 | class Baz: 1408 | x = 1 1409 | class Bar: 1410 | baz = Baz() 1411 | class Foo: 1412 | bar = Bar() 1413 | 1414 | foo = Foo() 1415 | foo = flexmock(foo) 1416 | foo.should_receive('bar.baz.x').and_return(2) 1417 | assertEqual(2, foo.bar.baz.x) 1418 | self._tear_down() 1419 | assertEqual(1, foo.bar.baz.x) 1420 | 1421 | def test_replace_non_callable_instance_attributes(self): 1422 | class Foo: 1423 | def __init__(self): 1424 | self.bar = 1 1425 | foo = Foo() 1426 | bar = Foo() 1427 | flexmock(foo, bar=2) 1428 | flexmock(bar, bar=1) 1429 | assertEqual(2, foo.bar) 1430 | self._tear_down() 1431 | assertEqual(1, foo.bar) 1432 | 1433 | def test_replace_non_callable_module_attributes(self): 1434 | if 'flexmock_test' in sys.modules: 1435 | mod = sys.modules['flexmock_test'] 1436 | else: 1437 | mod = sys.modules['__main__'] 1438 | flexmock(mod, module_level_attribute='yay') 1439 | assertEqual('yay', module_level_attribute) 1440 | self._tear_down() 1441 | assertEqual('test', module_level_attribute) 1442 | 1443 | def test_non_callable_attributes_fail_to_set_expectations(self): 1444 | class Foo: 1445 | bar = 1 1446 | foo = Foo() 1447 | e = flexmock(foo).should_receive('bar').and_return(2) 1448 | assertRaises(FlexmockError, e.times, 1) 1449 | assertRaises(FlexmockError, e.with_args, ()) 1450 | assertRaises(FlexmockError, e.replace_with, lambda x: x) 1451 | assertRaises(FlexmockError, e.and_raise, Exception) 1452 | assertRaises(FlexmockError, e.when, lambda x: x) 1453 | assertRaises(FlexmockError, e.and_yield, 1) 1454 | assertRaises(FlexmockError, object.__getattribute__(e, 'ordered')) 1455 | assertRaises(FlexmockError, object.__getattribute__(e, 'at_least')) 1456 | assertRaises(FlexmockError, object.__getattribute__(e, 'at_most')) 1457 | assertRaises(FlexmockError, object.__getattribute__(e, 'one_by_one')) 1458 | 1459 | def test_and_return_defaults_to_none_with_no_arguments(self): 1460 | foo = flexmock() 1461 | foo.should_receive('bar').and_return() 1462 | assertEqual(None, foo.bar()) 1463 | 1464 | def test_should_replace_attributes_that_are_instances_of_classes(self): 1465 | class Foo(object): 1466 | pass 1467 | class Bar(object): 1468 | foo = Foo() 1469 | bar = Bar() 1470 | flexmock(bar, foo='test') 1471 | assertEqual('test', bar.foo) 1472 | 1473 | def test_isproperty(self): 1474 | class Foo: 1475 | @property 1476 | def bar(self): pass 1477 | def baz(self): pass 1478 | class Bar(Foo): pass 1479 | foo = Foo() 1480 | bar = Bar() 1481 | assertEqual(True, _isproperty(foo, 'bar')) 1482 | assertEqual(False, _isproperty(foo, 'baz')) 1483 | assertEqual(True, _isproperty(Foo, 'bar')) 1484 | assertEqual(False, _isproperty(Foo, 'baz')) 1485 | assertEqual(True, _isproperty(bar, 'bar')) 1486 | assertEqual(False, _isproperty(bar, 'baz')) 1487 | assertEqual(True, _isproperty(Bar, 'bar')) 1488 | assertEqual(False, _isproperty(Bar, 'baz')) 1489 | assertEqual(False, _isproperty(Mock(), 'baz')) 1490 | 1491 | def test_fake_object_supporting_iteration(self): 1492 | foo = flexmock() 1493 | foo.should_receive('__iter__').and_yield(1, 2, 3) 1494 | assertEqual([1, 2, 3], [i for i in foo]) 1495 | 1496 | def test_with_args_for_single_named_arg_with_optional_args(self): 1497 | class Foo(object): 1498 | def bar(self, one, two='optional'): pass 1499 | e = flexmock(Foo).should_receive('bar') 1500 | e.with_args(one=1) 1501 | 1502 | def test_with_args_doesnt_set_max_when_using_varargs(self): 1503 | class Foo(object): 1504 | def bar(self, *kargs): pass 1505 | flexmock(Foo).should_receive('bar').with_args(1, 2, 3) 1506 | 1507 | def test_with_args_doesnt_set_max_when_using_kwargs(self): 1508 | class Foo(object): 1509 | def bar(self, **kwargs): pass 1510 | flexmock(Foo).should_receive('bar').with_args(1, 2, 3) 1511 | 1512 | def test_with_args_blows_up_on_too_few_args(self): 1513 | class Foo(object): 1514 | def bar(self, a, b, c=1): pass 1515 | e = flexmock(Foo).should_receive('bar') 1516 | assertRaises(MethodSignatureError, e.with_args, 1) 1517 | 1518 | def test_with_args_blows_up_on_too_few_args_with_kwargs(self): 1519 | class Foo(object): 1520 | def bar(self, a, b, c=1): pass 1521 | e = flexmock(Foo).should_receive('bar') 1522 | assertRaises(MethodSignatureError, e.with_args, 1, c=2) 1523 | 1524 | def test_with_args_blows_up_on_too_many_args(self): 1525 | class Foo(object): 1526 | def bar(self, a, b, c=1): pass 1527 | e = flexmock(Foo).should_receive('bar') 1528 | assertRaises(MethodSignatureError, e.with_args, 1, 2, 3, 4) 1529 | 1530 | def test_with_args_blows_up_on_kwarg_overlapping_positional(self): 1531 | class Foo(object): 1532 | def bar(self, a, b, c=1, **kwargs): pass 1533 | e = flexmock(Foo).should_receive('bar') 1534 | assertRaises(MethodSignatureError, e.with_args, 1, 2, 3, c=2) 1535 | 1536 | def test_with_args_blows_up_on_invalid_kwarg(self): 1537 | class Foo(object): 1538 | def bar(self, a, b, c=1): pass 1539 | e = flexmock(Foo).should_receive('bar') 1540 | assertRaises(MethodSignatureError, e.with_args, 1, 2, d=2) 1541 | 1542 | def test_with_args_ignores_invalid_args_on_flexmock_instances(self): 1543 | foo = flexmock(bar=lambda x: x) 1544 | foo.should_receive('bar').with_args('stuff') 1545 | foo.bar('stuff') 1546 | 1547 | def test_with_args_does_not_compensate_for_self_on_static_instance_methods(self): 1548 | class Foo(object): 1549 | @staticmethod 1550 | def bar(x): pass 1551 | foo = Foo() 1552 | flexmock(foo).should_receive('bar').with_args('stuff') 1553 | foo.bar('stuff') 1554 | 1555 | def test_with_args_does_not_compensate_for_self_on_static_class_methods(self): 1556 | class Foo(object): 1557 | @staticmethod 1558 | def bar(x): pass 1559 | flexmock(Foo).should_receive('bar').with_args('stuff') 1560 | Foo.bar('stuff') 1561 | 1562 | def test_with_args_does_compensate_for_cls_on_class_methods(self): 1563 | class Foo(object): 1564 | @classmethod 1565 | def bar(cls, x): pass 1566 | foo = Foo() 1567 | flexmock(foo).should_receive('bar').with_args('stuff') 1568 | foo.bar('stuff') 1569 | 1570 | def test_calling_with_keyword_args_matches_mock_with_positional_args(self): 1571 | class Foo(object): 1572 | def bar(self, a, b, c): pass 1573 | foo = Foo() 1574 | flexmock(foo).should_receive('bar').with_args(1,2,3).once() 1575 | foo.bar(a=1, b=2, c=3) 1576 | 1577 | def test_calling_with_positional_args_matches_mock_with_kwargs(self): 1578 | class Foo(object): 1579 | def bar(self, a, b, c): pass 1580 | foo = Foo() 1581 | flexmock(foo).should_receive('bar').with_args(a=1,b=2,c=3).once() 1582 | foo.bar(1, 2, c=3) 1583 | 1584 | def test_use_replace_with_for_callable_shortcut_kwargs(self): 1585 | class Foo(object): 1586 | def bar(self): return 'bar' 1587 | foo = Foo() 1588 | flexmock(foo, bar=lambda: 'baz') 1589 | assertEqual('baz', foo.bar()) 1590 | 1591 | def test_mock_property_with_attribute_on_instance(self): 1592 | class Foo(object): 1593 | @property 1594 | def bar(self): return 'bar' 1595 | foo = Foo() 1596 | foo2 = Foo() 1597 | foo3 = Foo() 1598 | flexmock(foo, bar='baz') 1599 | flexmock(foo2, bar='baz2') 1600 | assertEqual('baz', foo.bar) 1601 | assertEqual('baz2', foo2.bar) 1602 | assertEqual('bar', foo3.bar) 1603 | self._tear_down() 1604 | assertEqual(False, hasattr(Foo, '_flexmock__bar'), 1605 | 'Property bar not cleaned up') 1606 | assertEqual('bar', foo.bar) 1607 | assertEqual('bar', foo2.bar) 1608 | assertEqual('bar', foo3.bar) 1609 | 1610 | def test_mock_property_with_attribute_on_class(self): 1611 | class Foo(object): 1612 | @property 1613 | def bar(self): return 'bar' 1614 | foo = Foo() 1615 | foo2 = Foo() 1616 | flexmock(Foo, bar='baz') 1617 | assertEqual('baz', foo.bar) 1618 | assertEqual('baz', foo2.bar) 1619 | self._tear_down() 1620 | assertEqual(False, hasattr(Foo, '_flexmock__bar'), 1621 | 'Property bar not cleaned up') 1622 | assertEqual('bar', foo.bar) 1623 | assertEqual('bar', foo2.bar) 1624 | 1625 | 1626 | class TestFlexmockUnittest(RegularClass, unittest.TestCase): 1627 | def tearDown(self): 1628 | pass 1629 | 1630 | def _tear_down(self): 1631 | return flexmock_teardown() 1632 | 1633 | 1634 | if sys.version_info >= (2, 6): 1635 | import flexmock_modern_test 1636 | 1637 | class TestUnittestModern(flexmock_modern_test.TestFlexmockUnittestModern): 1638 | pass 1639 | 1640 | 1641 | if sys.version_info >= (3, 0): 1642 | import py3_only_features 1643 | 1644 | class TestPy3Features(unittest.TestCase): 1645 | def test_mock_kwargs_only_func_mock_all(self): 1646 | flexmock(py3_only_features).should_receive( 1647 | 'kwargs_only_func').with_args(1, bar=2, baz=3).and_return(123) 1648 | self.assertEqual(py3_only_features.kwargs_only_func(1, bar=2, baz=3), 1649 | 123) 1650 | 1651 | def test_mock_kwargs_only_func_mock_required(self): 1652 | flexmock(py3_only_features).should_receive( 1653 | 'kwargs_only_func').with_args(1, bar=2).and_return(123) 1654 | self.assertEqual(py3_only_features.kwargs_only_func(1, bar=2), 123) 1655 | 1656 | def test_mock_kwargs_only_func_fails_if_required_not_provided(self): 1657 | self.assertRaises( 1658 | MethodSignatureError, 1659 | flexmock(py3_only_features).should_receive( 1660 | 'kwargs_only_func').with_args, 1661 | 1) 1662 | 1663 | 1664 | if __name__ == '__main__': 1665 | unittest.main() 1666 | -------------------------------------------------------------------------------- /tests/flexmock_unittest_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest 3 | 4 | from flexmock_test import TestFlexmockUnittest 5 | 6 | if sys.version_info >= (2, 6): 7 | from flexmock_modern_test import TestFlexmockUnittestModern 8 | 9 | if sys.version_info >= (3,0): 10 | from flexmock_test import TestPy3Features 11 | 12 | if __name__ == '__main__': 13 | unittest.main() 14 | -------------------------------------------------------------------------------- /tests/py3_only_features.py: -------------------------------------------------------------------------------- 1 | def kwargs_only_func(foo, *, bar, baz=5): 2 | return foo + bar + baz 3 | -------------------------------------------------------------------------------- /tests/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PYTHON_IMPLEMENTATIONS=${PYTHON_IMPLEMENTATIONS:-"python pypy jython"} 4 | python_VERSIONS=${PYTHON_VERSIONS:-"2.6 2.7 3.3 3.4 3.5"} 5 | pypy_VERSIONS=${PYPY_VERSIONS:-"nover 3"} 6 | jython_VERSIONS=${JYTHON_VERSIONS:-"nover"} 7 | 8 | if [ -z "$PYEXECS" ]; then 9 | for impl in $PYTHON_IMPLEMENTATIONS; do 10 | IMPL_VERSIONS_VAR=${impl}_VERSIONS 11 | for ver in ${!IMPL_VERSIONS_VAR}; do 12 | if [ "$ver" == "nover" ]; then 13 | PYEXECS="$PYEXECS $impl" 14 | else 15 | PYEXECS="$PYEXECS $impl$ver" 16 | fi 17 | done 18 | done 19 | fi 20 | 21 | RUNNERS=${RUNNERS:-"unittest nose pytest twisted"} 22 | SCRIPT=$(cd ${0%/*} && echo $PWD/${0##*/}) 23 | TEST_PATH=$(dirname $SCRIPT) 24 | FLEXMOCK_PATH=$(echo $TEST_PATH | sed -e s/tests$//) 25 | export PYTHONPATH=$FLEXMOCK_PATH:$TEST_PATH:$PYTHONPATH 26 | 27 | for pyexec in $PYEXECS; do 28 | if [[ "$RUNNERS" =~ unittest ]]; then 29 | echo unittest for $pyexec 30 | if test -f "`which $pyexec 2>/dev/null`"; then 31 | $pyexec $TEST_PATH/flexmock_unittest_test.py 32 | else 33 | echo $pyexec NOT FOUND 34 | fi 35 | fi 36 | 37 | if [[ "$RUNNERS" =~ nose ]]; then 38 | if $pyexec -c 'import nose' 2>/dev/null; then 39 | echo nose for $pyexec 40 | $pyexec -m nose $TEST_PATH/flexmock_nose_test.py 41 | else 42 | echo nose for $pyexec NOT FOUND 43 | fi 44 | fi 45 | 46 | if [[ "$RUNNERS" =~ pytest ]]; then 47 | if $pyexec -c 'import py.test' 2>/dev/null; then 48 | echo py.test for $pyexec 49 | $pyexec -m py.test $TEST_PATH/flexmock_pytest_test.py 50 | else 51 | echo py.test for $pyexec NOT FOUND 52 | fi 53 | fi 54 | 55 | if [[ "$RUNNERS" =~ twisted ]]; then 56 | if $pyexec -c "from twisted.scripts.trial import run" 2>/dev/null; then 57 | echo twisted for $pyexec 58 | $pyexec -c "from twisted.scripts.trial import run; run();" $TEST_PATH/flexmock_pytest_test.py 59 | rm -rf _trial_temp/ 60 | else 61 | echo twisted for $pyexec NOT FOUND 62 | fi 63 | fi 64 | done 65 | --------------------------------------------------------------------------------