././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1644454853.1073155 flexmock-0.11.3/CHANGELOG.md0000644000000000000000000000756200000000000012116 0ustar00# Changelog This project follows semantic versioning. Types of changes: - **Added**: New features. - **Changed**: Changes in existing functionality. - **Deprecated**: Soon-to-be removed features. - **Removed**: Removed features. - **Fixed**: Bug fixes. - **Infrastructure**: Changes in build or deployment infrastructure. - **Documentation**: Changes in documentation. ## Release 0.11.3 ### Added - Add PEP 561 `py.typed` marker file. ### Changed - Remove documentation and test files from wheels build. - Re-organize unit tests. ### Documentation - Add a warning about the usage of `.new_instances()` method in the documentation. ## Release 0.11.2 ### Fixed - Fix subunit testrunner integration is broken. - Fix: TeamCity (PyCharm) testrunner integration is broken. ### Infrastructure - Run tests with testtools, subunit, TeamCity, and doctest testrunners using tox. ### Documentation - Test flexmock API examples using doctest. - Re-add Sphinx support for generating man pages. - Fix 404 page not loading CSS and Javascript resources in documentation. - Small fixes to documentation. ## Release 0.11.1 ### Fixed - Fix Zope testrunner integration is broken. ### Infrastructure - Run tests with Zope testrunner using tox. ## Release 0.11.0 ### Added - Add Python 3.8, 3.9, 3.10, and 3.11 support. - Add type annotations. ### Changed - **BREAKING CHANGE**: Flexmock needs to be imported explicitly using `from flexmock import flexmock`. The hack that allowed flexmock to be imported directly using `import flexmock` did not work well with static analysis tools. - Many error messages have been improved. - Undocumented methods `Expectation.reset`, `Expectation.verify`, and `Expectation.match_args` that were unintentionally left public are now private methods. - Undocumented attributes in `Mock` and `Expectation` are now private. These attributes were never meant to be accessed directly. ### Removed - Drop Python 2.7, 3.4, 3.5 support. - Drop Pytest 4.x support. - Remove unittest2 and nose integrations. unittest2 and nose are not maintained anymore. - **BREAKING CHANGE**: Removed support for calling `once`, `twice`, `never`, and `mock` methods without parentheses. This allows code completion and static analysis to work with these methods. ### Fixed - Fix `should_call` is broken if called on a fake object. - Fix `and_raise` allows invalid arguments for an exception. ### Infrastructure - Run linters and tests using Github Actions. - Add coverage reporting using Codecov. ### Documentation - Add contribution documentation. - Use Mkdocs instead of Sphinx to build the documentation. ## Release 0.10.10 ### Fixed - Fix AttributeError raised when mocking a proxied object. ## Release 0.10.9 ### Fixed - Fix flexmock not mocking methods properly on derived classes. ## Release 0.10.8 ### Fixed - Fix `with_args` not working built-in functions. ## Release 0.10.7 ### Fixed - Fix `with_args` not working built-in functions and methods. - Fix previous pytest `--durations` fix not working. ## Release 0.10.6 ### Fixed - Fix flexmock broken with Pytest 4 & 5. - Fix new_instances method not working with Python 2.7. - Fix multiple expectations for the same classmethod are not matched. ## Release 0.10.5 ### Added - Improve error message on unmatched method signature expectation. ### Fixed - Fix using `should_call` passes wrong `runtime_self`. - Fix pytest `--durations` flag when flexmock is installed. ## Release 0.10.4 ### Added - Add Python 3.6 and 3.7 support. ### Removed - Drop Python 2.6, 3.3, and Jython support. ### Fixed - Don't hide exception when flexmock is used as context manager. - Fix expectation reset for static methods on PyPy 2. - Ensure original exception is not suppressed in pytest hook. Looking for older changelog entries? See [CHANGELOG](https://github.com/flexmock/flexmock/blob/884ed669e36140c514e362d2dee71433db1394f9/CHANGELOG) file in git history. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1629029293.7464533 flexmock-0.11.3/LICENSE0000644000000000000000000000277600000000000011314 0ustar00Copyright 2011-2015 Herman Sheremetyev, Slavek Kabrda. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/README.md0000644000000000000000000000766200000000000011565 0ustar00

banner

flexmock - Mock, stub, and spy library for Python.

pypi ci documentation codecov license

--- Flexmock is a testing library for Python that makes it easy to create mocks, stubs, and fakes. ## Features - **Mock**: Easily create mock objects and make assertions about which methods or attributes were used and arguments they were called with. - **Spy**: Proxy calls to object's original methods or attributes and make assertions based on return values or call count. - **Fake**: Generate a fake objects to be used in your tests with ease. - **Stub**: Create stub objects which replace parts of existing objects and classes with just one call. - **No external dependencies**: Flexmock is lightweight and only uses Python standard library. There are no external dependencies. - **Simple and intuitive**: Declarations are structured to read more like English sentences than API calls, so they are easy to learn and use. - **Fully type annotated**: External API is fully type annotated so it works great with static analysis tools and editor auto-completion. - **Integrations with test runners**: Integrates seamlessly with all major test runners like unittest, doctest, and pytest. - **Python 3.6+ and PyPy3**: Extensively tested to work with latest Python versions. ## Installation Install with pip: ``` pip install flexmock ``` ## Examples Flexmock features smooth integration with pretty much every popular test runner, so no special setup is necessary. Simply importing flexmock into your test module is sufficient to get started with any of the following examples: ```python from flexmock import flexmock ``` ### Mocks Assertions take many flavors and flexmock has many different facilities to generate them: ```python # Simplest is ensuring that a certain method is called flexmock(Train).should_receive("get_tickets").once() # Of course, it is also possible to provide a default return value flexmock(Train).should_receive("get_destination").and_return("Paris").once() # Or check that a method is called with specific arguments flexmock(Train).should_receive("set_destination").with_args("Seoul").at_least().twice() ``` ### Spies Instead of mocking, there are also times when you want to execute the actual method and simply find out how many times it was called. Flexmock uses `should_call` to generate this sort of assertions instead of `should_receive`: ```python # Verify that a method is called at most three times flexmock(Train).should_call("get_tickets").at_most().times(3) # Make sure that a method is never called with specific arguments flexmock(Train).should_call("set_destination").with_args("Helsinki").never() # More complex example with features like argument type and exception matching flexmock(Train).should_call("crash").with_args(str, int).and_raise(AttributeError).once() ``` See more examples in the documentation. ## Documentation User guide, examples, and a full API reference is available at: https://flexmock.readthedocs.io ## Contributing Contributions are absolutely welcome and encouraged! See [CONTRIBUTING.md](https://github.com/flexmock/flexmock/blob/master/CONTRIBUTING.md) to get started. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/docs/advanced/builtin_functions.md0000644000000000000000000000131100000000000017044 0ustar00# Mocking builtins Mocking or stubbing out builtin functions, such as `open()`, can be slightly tricky. It is not always obvious when the builtin function you are trying to mock might be internally called by the test runner and cause unexpected behavior in the test. As a result, the recommended way to mock out builtin functions is to always specify a fall-through with `should_call()` first and use `with_args()` to limit the scope of your mock or stub to just the specific invocation you are trying to replace: ```python mock = flexmock(__builtins__) mock.should_call("open") # set the fall-through mock.should_receive("open").with_args("file_name").and_return( flexmock(read=lambda: "some data") ) ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/docs/advanced/call_order.md0000644000000000000000000000117300000000000015422 0ustar00# Asserting call order Flexmock does not enforce call order by default, but it's easy to do if you need to: ```python flexmock(plane).should_receive("fly").with_args("left").and_return( "ok" ).ordered() flexmock(plane).should_receive("fly").with_args("right").and_return( "ok" ).ordered() ``` The order of the flexmock calls is the order in which these methods will need to be called by the code under test. If method `fly()` above is called with the right arguments in the declared order things will be fine and both will return `"ok"`. But trying to call `fly("right")` before `fly("left")` will result in an exception. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/docs/advanced/chained_methods.md0000644000000000000000000000346600000000000016441 0ustar00# Chained methods Let's say you have some code that looks something like the following: ```python http = HTTP() results = http.get_url("http://www.google.com").parse().display_results() ``` You could use flexmock to mock each of these method calls individually: ```python mock = flexmock( get_url=lambda: flexmock(parse=lambda: flexmock(display_results="ok")) ) flexmock(HTTP).new_instances(mock) ``` But that looks really error prone and quite difficult to read. Here is a better way: ```python mock = flexmock() flexmock(HTTP).new_instances(mock) mock.should_receive("get_url.parse.display_results").and_return("ok") ``` When using this short-hand, flexmock will create intermediate objects and expectations, returning the final one in the chain. As a result, any further modifications, such as `with_args()` or `times()` modifiers, will only be applied to the final method in the chain. If you need finer grained control, such as specifying specific arguments to an intermediate method, you can always fall back to the above long version. Word of caution: because flexmock generates temporary intermediate mock objects for each step along the chain, trying to mock two method call chains with the same prefix will not work. That is, doing the following will fail to set up the stub for `display_results()` because the one for `save_results()` overrides it: ```python flexmock(HTTP).should_receive("get_url.parse.display_results").and_return("ok") flexmock(HTTP).should_receive("get_url.parse.save_results").and_return("ok") ``` In this situation, you should identify the point where the chain starts to diverge and return a flexmock object that handles all the "tail" methods using the same object: ```python flexmock(HTTP).should_receive("get_url.parse").and_return( flexmock(display_results="ok", save_results="ok") ) ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/docs/advanced/generators.md0000644000000000000000000000117400000000000015466 0ustar00# Generators In addition to returning values and raising exceptions, flexmock can also turn the mocked method into a generator that yields successive values: ```python >>> flexmock(plane).should_receive("flight_log").and_yield( "take off", "flight", "landing") >>> for i in plane.flight_log(): >>> print(i) "take off" "flight" "landing" ``` You can also use Python's builtin `iter()` function to generate an iterable return value: ```python flexmock(plane, flight_log=iter(["take off", "flight", "landing"])) ``` In fact, the `and_yield()` modifier is just shorthand for `should_receive().and_return(iter)` under the hood. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4145355 flexmock-0.11.3/docs/advanced/multiple_return.md0000644000000000000000000000122400000000000016543 0ustar00# Multiple return values It is possible for the mocked method to return different values on successive calls: ```python >>> flexmock(group).should_receive("get_member").and_return("user1").and_return( "user2" ).and_return("user3") >>> group.get_member() "user1" >>> group.get_member() "user2" >>> group.get_member() "user3" ``` Or use the short-hand form ```python flexmock(group).should_receive("get_member").and_return( "user1", "user2", "user3" ).one_by_one() ``` You can also mix return values with exception raises ```python flexmock(group).should_receive("get_member").and_return("user1").and_raise( Exception ).and_return("user2") ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1644454840.8433993 flexmock-0.11.3/docs/advanced/new_instances.md0000644000000000000000000000333300000000000016154 0ustar00# Fake new instances Occasionally you will want a class to create fake objects when it is being instantiated. Flexmock makes it easy and painless. Your first option is to simply replace the class with a function: ```python flexmock(some_module).should_receive("NameOfClass").and_return(fake_instance) # fake_instance can be created with flexmock as well ``` The downside if this is that you may run into subtle issues since the class has now been replaced by a function. Flexmock offers another alternative using the `.new_instances()` method: !!!warning Usage of `.new_instances()` method is discouraged due to a bug in CPython which prevents proper teardown of the mock. Due to this bug, the mock leaks into other tests and can prevent creating new instances of the class. More information in [issue #16](https://github.com/flexmock/flexmock/issues/16). ```python >>> class Group: pass >>> fake_group = flexmock(name="fake") >>> flexmock(Group).new_instances(fake_group) >>> Group().name == "fake" True ``` It is also possible to return different fake objects in a sequence: ```python >>> class Group: pass >>> fake_group1 = flexmock(name="fake") >>> fake_group2 = flexmock(name="real") >>> flexmock(Group).new_instances(fake_group1, fake_group2) >>> Group().name == "fake" True >>> Group().name == "real" True ``` Another approach, if you're familiar with how instance instatiation is done in Python, is to stub the `__new__` method directly: ```python >>> flexmock(Group).should_receive("__new__").and_return(fake_group) >>> # or, if you want to be even slicker >>> flexmock(Group, __new__=fake_group) ``` In fact, the new_instances command is simply shorthand for `should_receive("__new__").and_return()` under the hood. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/advanced/replacing_functions.md0000644000000000000000000000131100000000000017342 0ustar00# Replacing methods There are times when it is useful to replace a method with a custom lambda or function, rather than simply stubbing it out, in order to return custom values based on provided arguments or a global value that changes between method calls. ```python flexmock(plane).should_receive("set_speed").replace_with(lambda x: x == 5) ``` There is also shorthand for this, similar to the shorthand for `should_receive`/`and_return`: ```python flexmock(plane, set_speed=lambda x: x == 5) ``` !!!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().` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/advanced/state.md0000644000000000000000000000240400000000000014432 0ustar00# Conditional assertions Flexmock supports conditional assertions based on external state. Consider the rather contrived `Radio` class with the following methods: ```python class Radio: is_on = False def __init__(self): self.volume = 0 def switch_on(self): self.is_on = True def switch_off(self): self.is_on = False def select_channel(self): return None def adjust_volume(self, num): self.volume = num radio = Radio() ``` Now we can define some method call expectations dependent on the state of the radio: ```python flexmock(radio) radio.should_receive("select_channel").when(lambda: radio.is_on).once() radio.should_call("adjust_volume").with_args(5).when(lambda: radio.is_on).once() ``` Calling these while the radio is off will result in an error: ```python radio.select_channel() # Traceback (most recent call last): # flexmock.StateError: select_channel expected to be called # when condition is True ``` ```python radio.adjust_volume(5) # Traceback (most recent call last): # flexmock.StateError: adjust_volume expected to be called # when condition is True ``` Turning the radio on will make things work as expected: ```python radio.is_on = True radio.select_channel() radio.adjust_volume(5) ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/api.md0000644000000000000000000000012400000000000012313 0ustar00# API reference ::: flexmock.flexmock ::: flexmock.Mock ::: flexmock.Expectation ././@PaxHeader0000000000000000000000000000003000000000000010206 xustar0024 mtime=1638319852.722 flexmock-0.11.3/docs/changelog.md0000644000000000000000000000017600000000000013500 0ustar00 {!../CHANGELOG.md!} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1639206773.6128378 flexmock-0.11.3/docs/compare.md0000644000000000000000000001141100000000000013171 0ustar00# Mock library comparison This document shows a side-by-side comparison of how to accomplish some basic tasks with flexmock compared to Python unittest Mock. !!!note Note that in comparison to standard library unittest, flexmock also does automatic cleanup. This avoids leaking mocks to other tests in your test suite. ## Simple fake object (attributes only): ```python # flexmock my_mock = flexmock(some_attribute="value", some_other_attribute="value2") assert my_mock.some_attribute == "value" assert my_mock.some_other_attribute == "value2" # Mock my_mock = mock.Mock() my_mock.some_attribute = "value" my_mock.some_other_attribute = "value2" assert my_mock.some_attribute == "value" assert my_mock.some_other_attribute == "value2" ``` ## Simple fake object (with methods) ```python # flexmock my_mock = flexmock(some_method=lambda: "calculated value") assert my_mock.some_method() == "calculated value" # Mock my_mock = mock.Mock() my_mock.some_method.return_value = "calculated value" assert my_mock.some_method() == "calculated value" ``` ## Simple mock ```python # flexmock my_mock = flexmock() my_mock.should_receive("some_method").and_return("value").once() assert my_mock.some_method() == "value" # Mock my_mock = mock.Mock() my_mock.some_method.return_value = "value" assert my_mock.some_method() == "value" my_mock.some_method.assert_called_once_with() ``` ## Creating partial mocks ```python # flexmock flexmock(SomeClass).should_receive("some_method").and_return("value") assert SomeClass.some_method() == "value" # Mock with mock.patch("SomeClass") as my_mock: my_mock.some_method.return_value = "value" assert SomeClass.some_method() == "value" ``` ## Ensure calls are made in specific order ```python # flexmock my_mock = flexmock(SomeClass) my_mock.should_receive("method1").ordered().and_return("first thing").once() my_mock.should_receive("method2").ordered().and_return("second thing").once() # execute the code # Mock my_mock = mock.Mock(spec=SomeClass) my_mock.method1.return_value = "first thing" my_mock.method2.return_value = "second thing" # execute the code assert my_mock.method_calls == [("method1",), ("method2",)] ``` ## Raising exceptions ```python # flexmock my_mock = flexmock() my_mock.should_receive("some_method").and_raise(SomeException, "message") assertRaises(SomeException, my_mock.some_method) # Mock my_mock = mock.Mock() my_mock.some_method.side_effect = SomeException("message") assertRaises(SomeException, my_mock.some_method) ``` ## Override new instances of a class ```python # flexmock flexmock(some_module.SomeClass).new_instances(some_other_object) assert some_other_object == some_module.SomeClass() # Mock with mock.patch("somemodule.SomeClass") as MockClass: MockClass.return_value = some_other_object assert some_other_object == some_module.SomeClass() ``` ## Verify a method was called multiple times ```python # flexmock (verifies that the method gets called at least twice) flexmock(some_object).should_receive("some_method").at_least().twice() # execute the code # Mock my_mock = mock.Mock(spec=SomeClass) # execute the code assert my_mock.some_method.call_count >= 2 ``` ## Mock chained methods ```python # flexmock # (intermediate method calls are automatically assigned to temporary fake # objects and can be called with any arguments) flexmock(some_object).should_receive("method1.method2.method3").with_args( arg1, arg2 ).and_return("some value") assert some_object.method1().method2().method3(arg1, arg2) == "some_value" # Mock my_mock = mock.Mock() my_mock.method1.return_value.method2.return_value.method3.return_value = ( "some value" ) method3 = my_mock.method1.return_value.method2.return_value.method3 method3.assert_called_once_with(arg1, arg2) assert my_mock.method1().method2().method3(arg1, arg2) == "some_value" ``` ## Mock context manager ```python # flexmock my_mock = flexmock() with my_mock: pass # Mock my_mock = mock.MagicMock() with my_mock: pass ``` ## Mocking the builtin open used as a context manager The following examples work in an interactive Python session but may not work quite the same way in a script. See examples in the [Mocking builtins](advanced/builtin_functions.md) section for more specific flexmock instructions on mocking builtins. ```python # flexmock flexmock(__builtins__).should_receive("open").with_args("file_name").and_return( flexmock(read=lambda: "some data") ).once() with open("file_name") as file: assert file.read() == "some data" # Mock with mock.patch("builtins.open") as my_mock: my_mock.return_value.__enter__ = lambda s: s my_mock.return_value.__exit__ = mock.Mock() my_mock.return_value.read.return_value = "some data" with open("file_name") as file: assert file.read() == "some data" my_mock.assert_called_once_with("file_name") ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1639206773.6128378 flexmock-0.11.3/docs/conf.py0000644000000000000000000000236600000000000012531 0ustar00"""Flexmock Sphinx documentation configuration file. This file adds Sphinx support for documentation so that man pages can be generated using Sphinx. """ import os import sys # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath("..")) # -- Project information ----------------------------------------------------- project = "flexmock" copyright = "2021, Slavek Kabrda, Herman Sheremetyev" # -- General configuration --------------------------------------------------- extensions = ["myst_parser"] source_suffix = { ".rst": "restructuredtext", ".md": "markdown", } master_doc = "toctree" exclude_patterns = ["api.md", "changelog.md", "contributing.md"] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ("toctree", "flexmock", "flexmock Documentation", ["Slavek Kabrda, Herman Sheremetyev"], 1) ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1638320433.0064087 flexmock-0.11.3/docs/contributing.md0000644000000000000000000000002700000000000014253 0ustar00{!../CONTRIBUTING.md!} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1639206773.6128378 flexmock-0.11.3/docs/index.md0000644000000000000000000000501500000000000012655 0ustar00# Overview

banner

flexmock - Mock, stub, and spy library for Python.

pypi ci documentation codecov license

---

Contribute: https://github.com/flexmock/flexmock
Download: https://pypi.python.org/pypi/flexmock

--- Flexmock is a testing library for Python. Its API is inspired by a Ruby library of the same name. However, it is not a goal of Python flexmock to be a clone of the Ruby version. Instead, the focus is on providing full support for testing Python programs and making the creation of fake objects as unobtrusive as possible. As a result, Python flexmock removes a number of redundancies in the Ruby flexmock API, alters some defaults, and introduces several Python-only features. Flexmock's design focuses on simplicity and intuitiveness. This means that the API is as lean as possible, though a few convenient short-hand methods are provided to aid brevity and readability. Flexmock declarations are structured to read more like English sentences than API calls, and it is possible to chain them together in any order to achieve a high degree of expressiveness in a single line of code. ## Installation Install with pip: ``` pip install flexmock ``` ## Compatibility Tested to work with: - Python 3.6 - Python 3.7 - Python 3.8 - Python 3.9 - Python 3.10 - PyPy3 Automatically integrates with all major test runners, including: - unittest - pytest - django - twisted / trial - doctest - zope.testrunner - subunit - testtools ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/start.md0000644000000000000000000001114400000000000012703 0ustar00# Getting started So what does flexmock actually help you do? ## Setup Flexmock features smooth integration with pretty much every popular test runner, so no special setup is necessary. Simply importing flexmock into your test module is sufficient to get started with any of the following examples. ```python from flexmock import flexmock ``` This will include flexmock in your test and make the necessary runner modifications so no further setup or cleanup is necessary. ## Creating fake objects Making a new object in Python requires defining a new class with all the fake methods and attributes you are interested in emulating and then instantiating it. 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 this: ```python class FakePlane: operational = True model = "MIG-21" def fly(self): pass plane = FakePlane() # this is tedious! ``` 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. Flexmock provides an easier way to generate a fake object on the fly using the `flexmock()` function: ```python plane = flexmock(operational=True, model="MIG-21") ``` 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: ```python plane = flexmock(operational=True, model="MIG-21", fly=lambda: None) ``` ## Stubs While creating fake objects from scratch is often sufficient, many times it is easier to take an existing object and simply stub out certain methods or replace them with fake ones. Flexmock makes this easy as well: ```python flexmock( Train, # this can be an instance, a class, or a module get_destination="Tokyo", get_speed=200, ) ``` By passing a real object (or class or module) into the `flexmock()` function as the first argument it is possible to modify that object in place and provide default return values for any of its existing methods. In addition to simply stubbing out return values, it can be useful to be able to call an entirely different method and substitute return values based on test-specific conditions: ```python flexmock(Train).should_receive("get_route").replace_with( lambda x: custom_get_route() ) ``` ## Mocks Expectations take many flavors, and flexmock has many different facilities and modes to generate them. The first and simplest is ensuring that a certain method is called: ```python flexmock(Train).should_receive("get_destination").once() ``` The `.once()` modifier ensures that `Train.get_destination()` is called at some point during the test and will raise an exception if this does not happen. Of course, it is also possible to provide a default return value: ```python flexmock(Train).should_receive("get_destination").and_return("Tokyo").once() ``` Or check that a method is called with specific arguments: ```python flexmock(Train).should_receive("set_destination").with_args( "Tokyo" ).at_least().times(1) ``` In this example we used `.times(1)` instead of `.once()` and added the `.at_least()` modifier to demonstate that it is easy to match any number of calls, including 0 calls or a variable amount of calls. As you've probably guessed there is also an `at_most()` modifier. ## Spies While replacing method calls with canned return values or checking that they are called with specific arguments is quite useful, there are also times when you want to execute the actual method and simply find out how many times it was called. Flexmock uses `should_call()` to generate this sort of expectations instead of `should_receive()`: ```python flexmock(Train).should_call("get_destination").once() ``` In the above case the real `get_destination()` method will be executed, but flexmock will raise an exception unless it is executed exactly once. All the modifiers allowed with `should_receive()` can also be used with `should_call()` so it is possible to tweak the allowed arguments, return values, and call counts. ```python flexmock(Train).should_call("set_destination").with_args( object, str, int ).and_raise(Exception, re.compile("^No such dest.*")).once() ``` The above example introduces a handful of new capabilities -- matching exceptions, matching argument types (object naturally matches any argument type) and regex matching on string return values and arguments. ## Summary Flexmock has many other features and capabilities, but hopefully the above overview has given you enough of the flavor for the kind of things that it makes possible. For more details see the [User Guide](usage/intro.md). ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1639206773.6128378 flexmock-0.11.3/docs/toctree.rst0000644000000000000000000000055500000000000013427 0ustar00Overview ======== .. toctree:: index start usage/intro usage/mocking usage/spying usage/call_count usage/argument_matching advanced/builtin_functions advanced/call_order advanced/chained_methods advanced/generators advanced/multiple_return advanced/new_instances advanced/replacing_functions advanced/state compare ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/usage/argument_matching.md0000644000000000000000000000611600000000000016351 0ustar00# Argument matching Creating an expectation with no arguments will by default match all arguments, including no arguments. ```python flexmock(plane).should_receive("fly").and_return("ok") ``` Above will be matched by any of the following: ```python >>> plane.fly() "ok" >>> plane.fly("up") "ok" >>> plane.fly("up", "down") "ok" ``` You can also match exactly no arguments: ```python flexmock(plane).should_receive("fly").with_args() ``` Or match any single argument: ```python flexmock(plane).should_receive("fly").with_args("left") ``` ## Matching argument types In addition to exact values, you can match against the type or class of the argument: ```python flexmock(plane).should_receive("fly").with_args(object) ``` Match any single string argument ```python flexmock(plane).should_receive("fly").with_args(str) ``` Match the empty string using a compiled regular expression: ```python regex = re.compile("^(up|down)$") flexmock(plane).should_receive("fly").with_args(regex) ``` Match any set of three arguments where the first one is an integer, second one is anything, and third is string 'notes' (matching against user defined classes is also supported in the same fashion): ```python flexmock(plane).should_receive("repair").with_args(int, object, "notes") ``` If the default argument matching based on types is not flexible enough, flexmock will respect matcher objects that provide a custom `__eq__` method. For example, when trying to match against contents of numpy arrays, equality is undefined by the library so comparing two of them directly is meaningless unless you use `all()` or `any()` on the return value of the comparison. What you can do in this case is create a custom matcher object and flexmock will use its `__eq__` method when comparing the arguments at runtime. ```python class NumpyArrayMatcher: def __init__(self, array): self.array = array def __eq__(self, other): return all(other == self.array) flexmock(obj).should_receive("function").with_args(NumpyArrayMatcher(array1)) ``` The above approach will work for any objects that choose not to return proper boolean comparison values, or if you simply find the default equality and type-based matching not sufficiently specific. ## Multiple argument expectations It is also possible to create multiple expectations for the same method differentiated by arguments. ```python flexmock(plane).should_receive("fly").and_return("ok") flexmock(plane).should_receive("fly").with_args("up").and_return("bad") ``` Try to excecute `plane.fly()` with any, or no, arguments as defined by the first flexmock call will return the first value. ```python >>> plane.fly() "ok" >>> plane.fly("forward", "down") "ok" ``` But! If argument values match the more specific flexmock call the function will return the other return value: ```python >>> plane.fly("up") "bad" ``` The order of the expectations being defined is significant, with later expectations having higher precedence than previous ones. Which means that if you reversed the order of the example expectations above the more specific expectation would never be matched. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/usage/call_count.md0000644000000000000000000000164000000000000014775 0ustar00# Asserting call counts Using the `times(N)` modifier, or its aliases (`once`, `twice`, or `never`) allows you to create call count expectations that will be automatically checked by the test runner. !!! note If you do not provide `times` modifier. The mock is expected to be called zero or any number of times. In other words, the call count is not asserted. Ensure `fly("forward")` gets called exactly three times ```python flexmock(plane).should_receive("fly").with_args("forward").times(3) ``` Ensure `turn("east")` gets called at least twice: ```python flexmock(plane).should_receive("turn").with_args("east").at_least().twice() ``` Ensure `land("airfield")` gets called at most once: ```python flexmock(plane).should_receive("land").with_args("airfield").at_most().once() ``` Ensure that `crash("boom!")` is never called: ```python flexmock(plane).should_receive("crash").with_args("boom!").never() ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4185355 flexmock-0.11.3/docs/usage/intro.md0000644000000000000000000000307600000000000014012 0ustar00# Introduction In order to discuss flexmock usage it is important to define the following terms: - **Stub**: fake object that returns a canned value. - **Mock**: fake object that returns a canned value and has an expectation, i.e. it includes a built-in assertion. - **Spy**: watches method calls and records/verifies if the method is called with required parameters and/or returns expected values/exceptions. ## Overview Flexmock declarations follow a consistent style of the following three forms: 1. `flexmock ( OBJECT ).COMMAND( ATTRIBUTE ).MODIFIER[.MODIFIER, ...]` 2. `flexmock ( OBJECT [, ATTRIBUTE=VALUE, ...] )` 3. `flexmock ( ATTRIBUTE=VALUE [, ATTRIBUTE=VALUE,...] )` `OBJECT`: Either a module, a class, or an instance of a class. `COMMAND`: One of **should_receive**, **should_call**, or **new_instances**. These create the initial expectation object. `ATTRIBUTE`: String name of an attribute. `MODIFIER`: One of several Expectation modifiers, such as **with_args**, **and_return**, **and_raise**, or **times**. `VALUE`: Anything ## Style While the order of modifiers is unimportant to flexmock, there is a preferred convention that will make your tests more readable. If using `with_args()`, place it before `should_return()`, `and_raise()`, and `and_yield()` modifiers: ```python flexmock(plane).should_receive("fly").with_args("up", "down").and_return("ok") ``` If using the `times()` modifier (or its aliases: `once`, `twice`, `never`), place them at the end of the flexmock statement: ```python flexmock(plane).should_receive("fly").and_return("ok").once() ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4225354 flexmock-0.11.3/docs/usage/mocking.md0000644000000000000000000001004100000000000014274 0ustar00# Mocking ## Fake objects Create a fake object with no attributes: ```python fake = flexmock() ``` Specify attribute/return value pairs: ```python fake_plane = flexmock(model="MIG-16", condition="used") ``` Specify methods/return value pairs: ```python fake_plane = flexmock(fly=lambda: "voooosh!", land=lambda: "landed!") ``` You can mix method and non-method attributes by making the return value a lambda for callable attributes. Flexmock fake objects support the full range of flexmock commands but differ from partial mocks (described below) in that `should_receive()` can assign them new methods rather than being limited to acting on methods they already possess. ```python fake_plane = flexmock(fly=lambda: "vooosh!") fake_plane.should_receive("land").and_return("landed!") ``` ## Partial mocks Flexmock provides three syntactic ways to hook into an existing object and override its methods. Mark the object as partially mocked, allowing it to be used to create new expectations: ```python flexmock(plane) plane.should_receive("fly").and_return("vooosh!").once() plane.should_receive("land").and_return("landed!").once() ``` !!! 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`. Equivalent syntax assigns the partially mocked object to a variable: ```python plane = flexmock(plane) plane.should_receive("fly").and_return("vooosh!").once() plane.should_receive("land").and_return("landed!").once() ``` Or you can combine everything into one line if there is only one method to override: ```python flexmock(plane).should_receive("fly").and_return("vooosh!").once() ``` You can also return the mock object after setting the expectations: ```python plane = flexmock(plane).should_receive("fly").and_return("vooosh!").mock() ``` Note the `mock` modifier above -- the expectation chain returns an Expectation otherwise: ```python plane.should_receive("land").with_args().and_return("foo", "bar") ``` !!! 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. ## Attributes and properties Just as you are able to stub return values for functions and methods, flexmock also allows to stub out non-callable attributes and even (getter) properties. Syntax for this is exactly the same as for methods and functions. ### Shorthand Instead of writing out the lengthy `should_receive`/`and_return` statements, you can also use the handy shorthand approach of passing them in as key=value pairs to the `flexmock()` function. For example, we can stub out two methods of the plane object in the same call: ```python flexmock(plane, fly="voooosh!", land=("foo", "bar")) ``` This approach is handy and quick but only limited to stubs, i.e. it is not possible to further modify these kind of calls with any of the usual modifiers described below. ## Class level mocks If the object you partially mock is a class, flexmock effectively replaces the method for all instances of that class. ```python class User: def get_name(self): return "George Bush" flexmock(User) User.should_receive("get_name").and_return("Bill Clinton") bubba = User() bubba.get_name() # returns "Bill Clinton" ``` ## Raising exceptions You can make the mocked method raise an exception instead of returning a value: ```python flexmock(plane).should_receive("fly").and_raise(BadWeatherException) ``` You can also add a message to the exception being raised: ```python flexmock(plane).should_receive("fly").and_raise( BadWeatherException, "Oh noes, rain!" ) ``` ## Private methods One of the small pains of writing unit tests is that it can be difficult to get at the private methods since Python "conveniently" renames them when you try to access them from outside the object. With flexmock there is nothing special you need to do to -- mocking private methods is exactly the same as any other methods. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525703.4225354 flexmock-0.11.3/docs/usage/spying.md0000644000000000000000000000305600000000000014166 0ustar00# Spying In addition to stubbing out a given method and returning fake values, flexmock also allows you to call the original method and make expectations based on its return values/exceptions and the number of times the method is called with the given arguments. !!! note `should_call()` changes the behavior of `and_return()` and `and_raise()` to specify expectations rather than generate given values or exceptions. Matching specific arguments: ```python flexmock(plane).should_call("repair").with_args("wing", "cockpit").once() ``` Matching any arguments: ```python flexmock(plane).should_call("turn").twice() ``` Matching specific return values: ```python flexmock(plane).should_call("land").and_return("landed!") ``` Matching a regular expression: ```python flexmock(plane).should_call("land").and_return(re.compile("^la")) ``` Match return values by class/type: ```python flexmock(plane).should_call("fly").and_return(str, object, None) ``` Ensure that an appropriate exception is raised: ```python flexmock(plane).should_call("fly").and_raise(BadWeatherException) ``` Check that the exception message matches your expectations: ```python flexmock(plane).should_call("fly").and_raise( BadWeatherException, "Oh noes, rain!" ) ``` Check that the exception message matches a regular expression: ```python flexmock(plane).should_call("fly").and_raise( BadWeatherException, re.compile("rain") ) ``` If either `and_return()` or `and_raise()` is provided, flexmock will verify that the return value matches the expected return value or exception. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1644454880.5911262 flexmock-0.11.3/pyproject.toml0000644000000000000000000000642400000000000013215 0ustar00[tool.poetry] name = "flexmock" version = "0.11.3" description = "flexmock is a testing library for Python that makes it easy to create mocks, stubs and fakes." authors = ["Slavek Kabrda", "Herman Sheremetyev"] maintainers = [ "Adarsh Krishnan ", "Christophe Riolo Uusivaara ", "Olli Paakkunainen ", ] license = "BSD-2-Clause" repository = "https://github.com/flexmock/flexmock" documentation = "https://flexmock.readthedocs.io" readme = "README.md" keywords = ["mock", "testing", "test", "unittest", "pytest"] classifiers = [ "License :: OSI Approved :: BSD License", "Intended Audience :: Developers", "Development Status :: 5 - Production/Stable", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Testing", "Topic :: Software Development :: Testing :: Mocking", "Topic :: Software Development :: Testing :: Unit", "Typing :: Typed", ] include = [ { path = "CHANGELOG.md", format = "sdist" }, { path = "docs/**/*.md", format = "sdist" }, { path = "LICENSE", format = "sdist" }, { path = "README.md", format = "sdist" }, { path = "tests/**/*.py", format = "sdist" }, { path = "docs/conf.py", format = "sdist" }, { path = "docs/toctree.rst", format = "sdist" }, ] packages = [{ include = "flexmock", from = "src" }] [tool.poetry.urls] "Changes" = "https://flexmock.readthedocs.io/en/latest/changelog/" "Source Code" = "https://github.com/flexmock/flexmock" "Issue Tracker" = "https://github.com/flexmock/flexmock/issues" [tool.poetry.dependencies] python = "^3.6.2" [tool.poetry.dev-dependencies] pytest = "*" mypy = "*" pylint = "*" black = "*" isort = "*" tox = "*" Twisted = "*" pytest-cov = "*" mkdocs-material = "*" markdown-include = "*" mkdocstrings = "*" testtools = "*" myst-parser = "*" "zope.testrunner" = "*" python-subunit = "*" teamcity-messages = "*" [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" [tool.pylint.messages_control] disable = [ "too-many-instance-attributes", "too-few-public-methods", "too-many-function-args", "too-many-arguments", "too-many-locals", "too-many-branches", "too-many-statements", "too-many-public-methods", "protected-access", "broad-except", "fixme", "too-many-ancestors", ] [tool.pylint.format] max-line-length = "100" [tool.isort] line_length = 100 profile = "black" [tool.black] line_length = 100 [tool.mypy] warn_redundant_casts = true warn_unused_ignores = true ignore_missing_imports = true disallow_untyped_calls = true disallow_untyped_defs = true disallow_incomplete_defs = true check_untyped_defs = true disallow_untyped_decorators = true warn_return_any = true no_implicit_optional = true [[tool.mypy.overrides]] module = "tests.*" ignore_errors = true [tool.pytest.ini_options] python_files = ["test_pytest.py"] xfail_strict = true ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1637064346.2723827 flexmock-0.11.3/src/flexmock/__init__.py0000644000000000000000000000034300000000000015003 0ustar00"""Flexmock testing library for Python.""" from flexmock import _integrations # pylint: disable=unused-import from flexmock._api import Expectation, Mock, flexmock __all__ = [ "Expectation", "Mock", "flexmock", ] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1642036081.0123103 flexmock-0.11.3/src/flexmock/_api.py0000644000000000000000000016655400000000000014175 0ustar00"""Flexmock public API.""" # pylint: disable=no-self-use,too-many-lines import inspect import re import sys import types from types import BuiltinMethodType, TracebackType from typing import Any, Callable, Dict, Iterator, List, NoReturn, Optional, Tuple, Type from flexmock.exceptions import ( CallOrderError, ExceptionClassError, ExceptionMessageError, FlexmockError, MethodCallError, MethodSignatureError, MockBuiltinError, StateError, ) AT_LEAST = "at least" AT_MOST = "at most" EXACTLY = "exactly" SPECIAL_METHODS = (classmethod, staticmethod) UPDATED_ATTRS = ["should_receive", "should_call", "new_instances"] DEFAULT_CLASS_ATTRIBUTES = [attr for attr in dir(type) if attr not in dir(type("", (object,), {}))] # Fix Python 3.6 does not have re.Pattern type RE_TYPE = type(re.compile("")) class ReturnValue: """ReturnValue""" def __init__( self, value: Optional[Any] = None, raises: Optional[Type[BaseException]] = None ) -> None: self.value = value self.raises = raises def __str__(self) -> str: if self.raises: return f"{self.raises}({_arg_to_str(self.value)})" if not isinstance(self.value, tuple): return str(_arg_to_str(self.value)) if len(self.value) == 1: return str(_arg_to_str(self.value[0])) values = ", ".join([_arg_to_str(x) for x in self.value]) return f"({values})" class Mock: """Fake object class returned by the `flexmock()` function.""" def __init__(self, **kwargs: Any) -> None: """Mock constructor. Args: **kwargs: dict of attribute/value pairs used to initialize the mock object. """ self._object: Any = self for attr, value in kwargs.items(): if isinstance(value, property): setattr(self.__class__, attr, value) else: setattr(self, attr, value) def __enter__(self) -> Any: return self._object def __exit__( self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], traceback: Optional[TracebackType], ) -> None: pass def __call__(self, *args: Any, **kwargs: Any) -> "Mock": """Make mocks callable with and without parentheses. If `Mock` is not callable, it is difficult to mock attributes that should work with and without parentheses. """ return self def __iter__(self) -> Iterator[Any]: """Makes the mock object iterable. Call the instance's version of __iter__ if available, otherwise yield self. """ if ( hasattr(self, "__dict__") and isinstance(self.__dict__, dict) and "__iter__" in self.__dict__ ): for item in self.__dict__["__iter__"](self): yield item else: yield self def should_receive(self, name: str) -> "Expectation": """Replaces the specified attribute with a fake. Args: name: Name of the attribute to replace. Returns: Expectation object which can be used to modify the expectations on the fake attribute. Examples: >>> flexmock(plane).should_receive("fly").and_return("vooosh!").once() >>> plane.fly() 'vooosh!' """ if name in UPDATED_ATTRS: raise FlexmockError("unable to replace flexmock methods") chained_methods = None if "." in name: name, chained_methods = name.split(".", 1) name = self._update_name_if_mangled(name) self._ensure_object_has_named_attribute(name) if chained_methods: if not isinstance(self._object, Mock) and not hasattr( getattr(self._object, name), "__call__" ): # Create a partial mock if the given name is callable # this allows chaining attributes return_value = _create_partial_mock(getattr(self._object, name)) else: return_value = Mock() self._create_expectation(name, return_value) return return_value.should_receive(chained_methods) return self._create_expectation(name) def _update_name_if_mangled(self, name: str) -> str: """This allows flexmock to mock methods with name mangling.""" if name.startswith("__") and not name.endswith("__") and not inspect.ismodule(self._object): class_name: str if inspect.isclass(self._object): class_name = self._object.__name__ else: class_name = self._object.__class__.__name__ name = f"_{class_name.lstrip('_')}__{name.lstrip('_')}" return name def _ensure_object_has_named_attribute(self, name: str) -> None: if not isinstance(self._object, Mock) and not self._hasattr(self._object, name): if hasattr(self._object, "__name__"): obj_name = self._object.__name__ else: obj_name = str(self._object) raise FlexmockError(f"{obj_name} does not have attribute '{name}'") def _hasattr(self, obj: Any, name: str) -> bool: """Ensure hasattr checks don't create side-effects for properties.""" if not inspect.isclass(obj) and hasattr(obj, "__dict__") and name not in obj.__dict__: if name in DEFAULT_CLASS_ATTRIBUTES: return False # avoid false positives for things like __call__ return hasattr(obj.__class__, name) return hasattr(obj, name) def should_call(self, name: str) -> "Expectation": """Creates a spy. This means that the original method will be called rather than the fake version. However, we can still keep track of how many times it is called and with what arguments, and apply expectations accordingly. `should_call` is meaningless/not allowed for non-callable attributes. Args: name: Name of the method to spy. Returns: Expectation object. Examples: >>> flexmock(plane).should_call("repair").once() >>> plane.repair("wing") """ if isinstance(self._object, Mock) and not hasattr(self._object, name): raise FlexmockError( f"Mock object does not have attribute '{name}'. " f'Did you mean to call should_receive("{name}") instead?' ) expectation = self.should_receive(name) return expectation.replace_with(expectation.__dict__["_original"]) def new_instances(self, *args: Any) -> "Expectation": """Overrides `__new__` method on a class to return custom objects. Alias for `should_receive('__new__').and_return(args).one_by_one()`. Args: *args: Objects to return on each successive call to `__new__`. Returns: Expectation object. Examples: >>> fake_plane = flexmock(model="fake") >>> flexmock(Plane).new_instances(fake_plane) >>> Plane().model 'fake' It is also possible to return different fake objects in a sequence: >>> fake_plane1 = flexmock(model="fake1") >>> fake_plane2 = flexmock(model="fake2") >>> flexmock(Plane).new_instances(fake_plane1, fake_plane2) >>> Plane().model 'fake1' >>> Plane().model 'fake2' """ if inspect.isclass(self._object): return self.should_receive("__new__").and_return(args).one_by_one() raise FlexmockError("new_instances can only be called on a class mock") def _create_expectation(self, name: str, return_value: Optional[Any] = None) -> "Expectation": expectation = self._get_or_create_expectation(name, return_value) FlexmockContainer.add_expectation(self, expectation) if _isproperty(self._object, name): self._update_property(expectation, name) elif ( isinstance(self._object, Mock) or hasattr(getattr(self._object, name), "__call__") or inspect.isclass(getattr(self._object, name)) ): self._update_method(expectation, name) else: self._update_attribute(expectation, name, return_value) return expectation def _get_or_create_expectation( self, name: str, return_value: Optional[Any] = None ) -> "Expectation": saved_expectations = FlexmockContainer.get_expectations_with_name(self, name) if saved_expectations: # If there is already an expectation for the same name, get the # original object from the FIRST saved expectation. return Expectation( self._object, name=name, return_value=return_value, original=saved_expectations[0].__dict__.get("_original"), method_type=saved_expectations[0].__dict__.get("_method_type"), ) return Expectation(self._object, name=name, return_value=return_value) def _create_placeholder_mock_for_proper_teardown( self, obj: Any, name: str, original: Any ) -> None: """Ensures that the given function is replaced on teardown.""" mock = Mock() mock._object = obj expectation = Expectation(obj, name=name, original=original) FlexmockContainer.add_expectation(mock, expectation) def _update_method(self, expectation: "Expectation", name: str) -> None: method_instance = self._create_mock_method(name) if self._hasattr(self._object, name) and not hasattr(expectation, "_original"): expectation._update_original(name, self._object) expectation._method_type = self._get_method_type(name, expectation._original) if expectation._method_type in SPECIAL_METHODS: expectation._original_function = getattr(self._object, name) if not inspect.isclass(self._object) or expectation._method_type in SPECIAL_METHODS: method_instance = types.MethodType(method_instance, self._object) expectation._local_override = _setattr(self._object, name, method_instance) if ( expectation._local_override and not inspect.isclass(self._object) and not isinstance(self._object, Mock) and hasattr(self._object.__class__, name) ): self._update_class_for_magic_builtins(name) def _get_method_type(self, name: str, method: Callable[..., Any]) -> Any: """Get method type of the original method. Method type is saved because after mocking the base class, it is difficult to determine the original method type. """ method_type = self._get_saved_method_type(name, method) if method_type is not None: return method_type if _is_class_method(method, name): method_type = classmethod elif _is_static_method(self._object, name): method_type = staticmethod else: method_type = type(method) setattr(self._object, f"{name}__flexmock__method_type", method_type) return method_type def _get_saved_method_type(self, name: str, method: Callable[..., Any]) -> Optional[Any]: """Check method type of the original method if it was saved to the class or base class.""" bound_to = getattr(method, "__self__", None) if bound_to is not None and inspect.isclass(bound_to): # Check if the method type was saved in a base class for cls in inspect.getmro(bound_to): method_type = vars(cls).get(f"{name}__flexmock__method_type") if method_type: return method_type return None def _update_class_for_magic_builtins(self, name: str) -> None: """Fixes method resolution order for built-in methods. Replacing magic builtins on instances has no effect as the one attached to the class takes precedence. To work around it, we update the class' method to check if the instance in question has one in its own __dict__ and call that instead. """ if not (name.startswith("__") and name.endswith("__") and len(name) > 4): return original = getattr(self._object.__class__, name) def updated(self: Any, *kargs: Any, **kwargs: Any) -> Any: if ( hasattr(self, "__dict__") and isinstance(self.__dict__, dict) and name in self.__dict__ ): return self.__dict__[name](*kargs, **kwargs) return original(self, *kargs, **kwargs) setattr(self._object.__class__, name, updated) if updated.__code__ != original.__code__: self._create_placeholder_mock_for_proper_teardown( self._object.__class__, name, original ) def _update_attribute( self, expectation: "Expectation", name: str, return_value: Optional[Any] = None ) -> None: expectation._callable = False if self._hasattr(self._object, name) and not hasattr(expectation, "_original"): expectation._update_original(name, self._object) expectation._local_override = _setattr(self._object, name, return_value) def _update_property(self, expectation: "Expectation", name: str) -> None: new_name = f"_flexmock__{name}" obj = self._object if not inspect.isclass(obj): obj = obj.__class__ expectation._callable = False original = getattr(obj, name) @property # type: ignore def updated(self: Any) -> Any: if ( hasattr(self, "__dict__") and isinstance(self.__dict__, dict) and name in self.__dict__ ): return self.__dict__[name] # Return original for instances that are not mocked return getattr(self, new_name) setattr(obj, name, updated) if not hasattr(obj, new_name): # don't try to double update FlexmockContainer.add_teardown_property(obj, new_name) setattr(obj, new_name, original) self._create_placeholder_mock_for_proper_teardown(obj, name, original) def _create_mock_method(self, name: str) -> Callable[..., Any]: def _handle_exception_matching(expectation: Expectation) -> None: # pylint: disable=misplaced-bare-raise return_values = expectation._return_values if return_values: raised, instance = sys.exc_info()[:2] assert raised, "no exception was raised" message = str(instance) expected = return_values[0].raises if not expected: raise args = return_values[0].value if inspect.isclass(expected): assert isinstance(args, dict) expected_instance = expected(*args["kargs"], **args["kwargs"]) expected_message = str(expected_instance) if expected is not raised and expected not in raised.__bases__: raise ExceptionClassError( f"Raised exception for call {expectation._name} " "did not match expectation:\n" f" Expected:\t{expected}\n" f" Raised:\t{raised}" ) if args["kargs"] and isinstance(args["kargs"][0], RE_TYPE): if not args["kargs"][0].search(message): raise ExceptionMessageError( f"Error message mismatch with raised {expected.__name__}:\n" f" Expected pattern:\n\t/{args['kargs'][0].pattern}/\n" f" Received message:\n\t'{message}'" ) elif expected_message and expected_message != message: raise ( ExceptionMessageError( f"Error message mismatch with raised {expected.__name__}:\n" f" Expected message:\n\t'{message}'\n" f" Received message:\n\t'{expected_message}'" ) ) elif expected is not raised: raise ExceptionClassError( f"Raised exception for call {expectation._name} " f"did not match expectation:\n" f" Expected:\t{repr(expected)}\n" f" Raised:\t{raised}\n\n" "Did you try to call and_raise with an instance?\n" 'Instead of and_raise(Exception("arg")), try and_raise(Exception, "arg")' ) else: raise def match_return_values(expected: Any, received: Any) -> bool: if not isinstance(expected, tuple): expected = (expected,) if not isinstance(received, tuple): received = (received,) if len(received) != len(expected): return False for i, val in enumerate(received): if not _arguments_match(val, expected[i]): return False return True def pass_thru( expectation: Expectation, runtime_self: Any, *kargs: Any, **kwargs: Any ) -> Any: return_values = None try: original = expectation._original _mock = expectation._mock if inspect.isclass(_mock): if expectation._method_type in SPECIAL_METHODS: original = expectation._original_function return_values = original(*kargs, **kwargs) else: return_values = original(runtime_self, *kargs, **kwargs) else: return_values = original(*kargs, **kwargs) except Exception: return _handle_exception_matching(expectation) expected_values = expectation._return_values if expected_values and not match_return_values(expected_values[0].value, return_values): expected_value = expected_values[0].value # Display strings with quotes in the error message if isinstance(return_values, str): return_values = repr(return_values) if isinstance(expected_value, str): expected_value = repr(expected_value) raise ( MethodSignatureError( f"Returned values for call {expectation._name} did not match expectation:\n" f" Expected:\t{expected_value}\n" f" Returned:\t{return_values}" ) ) return return_values def _handle_matched_expectation( expectation: Expectation, runtime_self: Any, *kargs: Any, **kwargs: Any ) -> Any: if not expectation._runnable(): raise StateError( f"{name} expected to be called when {expectation._get_runnable()} is True" ) expectation._times_called += 1 expectation._verify(final=False) _pass_thru = expectation._pass_thru _replace_with = expectation._replace_with if _pass_thru: return pass_thru(expectation, runtime_self, *kargs, **kwargs) if _replace_with: return _replace_with(*kargs, **kwargs) return_values = expectation._return_values if return_values: return_value = return_values[0] del return_values[0] return_values.append(return_value) else: return_value = ReturnValue() if return_value.raises: if inspect.isclass(return_value.raises): args = return_value.value assert isinstance(args, dict) raise return_value.raises(*args["kargs"], **args["kwargs"]) raise return_value.raises # pylint: disable=raising-bad-type return return_value.value def mock_method(runtime_self: Any, *kargs: Any, **kwargs: Any) -> Any: arguments = {"kargs": kargs, "kwargs": kwargs} expectation = FlexmockContainer.get_flexmock_expectation(self, name, arguments) if expectation: return _handle_matched_expectation(expectation, runtime_self, *kargs, **kwargs) # inform the user which expectation(s) for the method were _not_ matched saved_expectations = reversed(FlexmockContainer.get_expectations_with_name(self, name)) error_msg = ( f"Arguments for call {name} did not match expectations:\n" f" Received call:\t{_format_args(name, arguments)}\n" ) if saved_expectations: error_msg += "\n".join( f" Expected call[{index}]:\t{_format_args(name, expectation._args)}" for index, expectation in enumerate(saved_expectations, 1) ) raise MethodSignatureError(error_msg) return mock_method def flexmock_teardown() -> None: """Performs flexmock-specific teardown tasks.""" saved = {} instances = [] classes = [] for mock_object, expectations in FlexmockContainer.flexmock_objects.items(): saved[mock_object] = expectations[:] for expectation in expectations: expectation._reset() for expectation in expectations: # Remove method type attributes set by flexmock. This needs to be done after # resetting all the expectations because method type is needed in expectation teardown. if inspect.isclass(mock_object) or hasattr(mock_object, "__class__"): try: delattr(mock_object._object, f"{expectation._name}__flexmock__method_type") except (AttributeError, TypeError): pass for mock in saved: obj = mock._object if not isinstance(obj, Mock) and not inspect.isclass(obj): instances.append(obj) if inspect.isclass(obj): classes.append(obj) for obj in instances + classes: for attr in UPDATED_ATTRS: try: obj_dict = obj.__dict__ if obj_dict[attr].__code__ is Mock.__dict__[attr].__code__: del obj_dict[attr] except Exception: try: if getattr(obj, attr).__code__ is Mock.__dict__[attr].__code__: delattr(obj, attr) except AttributeError: pass FlexmockContainer.teardown_properties() FlexmockContainer.reset() # make sure this is done last to keep exceptions here from breaking # any of the previous steps that cleanup all the changes for mock_object, expectations in saved.items(): for expectation in expectations: expectation._verify() class Expectation: """Holds expectations about methods. The information contained in the Expectation object includes method name, its argument list, return values, and any exceptions that the method might raise. """ def __init__( self, mock: Mock, name: Optional[str] = None, return_value: Optional[Any] = None, original: Optional[Any] = None, method_type: Optional[Any] = None, ) -> None: if original is not None: self._original = original self._name = name self._times_called: int = 0 self._modifier: str = EXACTLY self._args: Optional[Dict[str, Any]] = None self._method_type = method_type self._argspec: Optional[inspect.FullArgSpec] = None self._return_values = [ReturnValue(return_value)] if return_value is not None else [] self._replace_with: Optional[Callable[..., Any]] = None self._original_function: Optional[Callable[..., Any]] = None self._expected_calls: Dict[str, Optional[int]] = { EXACTLY: None, AT_LEAST: None, AT_MOST: None, } self._runnable: Callable[..., bool] = lambda: True self._mock = mock self._pass_thru = False self._ordered = False self._one_by_one = False self._verified = False self._callable = True self._local_override = False # Remove in 1.0. Issue #96 self._called_deprecated_property = False def __str__(self) -> str: args = _format_args(str(self._name), self._args) return_values = ", ".join(str(x) for x in self._return_values) return f"{args} -> ({return_values})" def __getattribute__(self, name: str) -> Any: # Workaround to raise an error if once, twice, or never are called # without parenthesis. if name in ("once", "twice", "never", "mock"): self._called_deprecated_property = True return object.__getattribute__(self, name) def _get_runnable(self) -> str: """Ugly hack to get the name of when() condition from the source code.""" name = "condition" try: source = inspect.getsource(self._runnable) if "when(" in source: name = source.split("when(")[1].split(")")[0] elif "def " in source: name = source.split("def ")[1].split("(")[0] except Exception: # couldn't get the source, oh well pass return name def _verify_signature_match(self, *kargs: Any, **kwargs: Any) -> None: if isinstance(self._mock, Mock): return # no sense in enforcing this for fake objects allowed = self._argspec args_len = len(allowed.args) # self is the first expected argument has_self = allowed.args and allowed.args[0] == "self" # Builtin methods take `self` as the first argument but `inspect.ismethod` returns False # so we need to check for them explicitly is_builtin_method = isinstance(self._original, BuiltinMethodType) and has_self # Methods take `self` if not a staticmethod is_method = inspect.ismethod(self._original) and self._method_type is not staticmethod # Class init takes `self` is_class = inspect.isclass(self._original) # When calling class methods or instance methods on a class method takes `cls` is_class_method = ( inspect.isfunction(self._original) and inspect.isclass(self._mock) and self._method_type is not staticmethod ) if is_builtin_method or is_method or is_class or is_class_method: # Do not count `self` or `cls`. args_len -= 1 minimum = args_len - (allowed.defaults and len(allowed.defaults) or 0) maximum = None if allowed.varargs is None and allowed.varkw is None: maximum = args_len total_positional = len(kargs + tuple(a for a in kwargs if a in allowed.args)) named_optionals = [ a for a in kwargs if allowed.defaults if a in allowed.args[len(allowed.args) - len(allowed.defaults) :] ] if allowed.defaults and total_positional == minimum and named_optionals: minimum += len(named_optionals) if total_positional < minimum: arguments = "argument" if minimum == 1 else "arguments" raise MethodSignatureError( f"{self._name} requires at least {minimum} {arguments}, " f"expectation provided {total_positional}" ) if maximum is not None and total_positional > maximum: arguments = "argument" if maximum == 1 else "arguments" raise MethodSignatureError( f"{self._name} requires at most {maximum} {arguments}, " f"expectation provided {total_positional}" ) if args_len == len(kargs) and any(a for a in kwargs if a in allowed.args): given_args = [a for a in kwargs if a in allowed.args] arguments = "argument" if len(given_args) == 1 else "arguments" raise MethodSignatureError( f"{given_args} already given as positional {arguments} to {self._name}" ) if not allowed.varkw and any( a for a in kwargs if a not in allowed.args + allowed.kwonlyargs ): invalid_arg = [a for a in kwargs if a not in allowed.args + allowed.kwonlyargs][0] raise MethodSignatureError( f"{invalid_arg} is not a valid keyword argument to {self._name}" ) # check that kwonlyargs that don't have default value specified are provided required_kwonlyargs = [ a for a in allowed.kwonlyargs if a not in (allowed.kwonlydefaults or {}) ] missing_kwonlyargs = [a for a in required_kwonlyargs if a not in kwargs] if missing_kwonlyargs: arguments = "argument" if len(missing_kwonlyargs) == 1 else "arguments" missing_args = '", "'.join(missing_kwonlyargs) raise MethodSignatureError( f'{self._name} requires keyword-only {arguments} "{missing_args}"' ) def _update_original(self, name: str, obj: Any) -> None: if hasattr(obj, "__dict__") and name in obj.__dict__: self._original = obj.__dict__[name] else: self._original = getattr(obj, name) self._update_argspec() def _update_argspec(self) -> None: original = self.__dict__.get("_original") if original: try: self._argspec = inspect.getfullargspec(original) except TypeError: # built-in function: fall back to stupid processing and hope the # builtins don't change signature pass def _normalize_named_args(self, *kargs: Any, **kwargs: Any) -> Dict[str, Any]: argspec = self._argspec default = {"kargs": kargs, "kwargs": kwargs} if not argspec: return default ret: Dict[str, Any] = {"kargs": (), "kwargs": kwargs} if inspect.ismethod(self._original): args = argspec.args[1:] else: args = argspec.args for i, arg in enumerate(kargs): if len(args) <= i: return default ret["kwargs"][args[i]] = arg return ret def __raise(self, exception: Type[BaseException], message: str) -> NoReturn: """Safe internal raise implementation. In case we're patching builtins, it's important to reset the expectation before raising any exceptions or else things like open() might be stubbed out and the resulting runner errors are very difficult to diagnose. """ self._reset() raise exception(message) def _match_args(self, given_args: Any) -> bool: """Check if the set of given arguments matches this expectation.""" expected_args = self._args given_args = self._normalize_named_args(*given_args["kargs"], **given_args["kwargs"]) if expected_args == given_args or expected_args is None: return True if ( len(given_args["kargs"]) != len(expected_args["kargs"]) or len(given_args["kwargs"]) != len(expected_args["kwargs"]) or (sorted(given_args["kwargs"].keys()) != sorted(expected_args["kwargs"].keys())) ): return False for i, arg in enumerate(given_args["kargs"]): if not _arguments_match(arg, expected_args["kargs"][i]): return False for key, value in given_args["kwargs"].items(): if not _arguments_match(value, expected_args["kwargs"][key]): return False return True def mock(self) -> Mock: """Return the mock associated with this expectation. Returns: Mock associated with this expectation. Examples: >>> plane = flexmock(plane).should_receive("fly").mock() """ self._called_deprecated_property = False return self._mock def with_args(self, *args: Any, **kwargs: Any) -> "Expectation": """Override the arguments used to match this expectation's method. Args: *args: Positional arguments. **kwargs: Keyword arguments. Returns: Self, i.e. can be chained with other Expectation methods. Examples: Match calls with no arguments: >>> flexmock(plane).should_receive("fly").with_args() Match a single argument: >>> flexmock(plane).should_receive("fly").with_args("east") Match keyword arguments: >>> flexmock(plane).should_receive("fly").with_args("up", destination="Oslo") Match argument type: >>> flexmock(plane).should_receive("fly").with_args(str) Match a string using a compiled regular expression: >>> regex = re.compile("^(up|down)$") >>> flexmock(plane).should_receive("fly").with_args(regex) """ if not self._callable: self.__raise(FlexmockError, "can't use with_args() with attribute stubs") self._update_argspec() if self._argspec: # do this outside try block as TypeError is way too general and catches # unrelated errors in the verify signature code self._verify_signature_match(*args, **kwargs) self._args = self._normalize_named_args(*args, **kwargs) else: self._args = {"kargs": args, "kwargs": kwargs} return self def and_return(self, *values: Any) -> "Expectation": """Override the return value of this expectation's method. When `and_return` is given multiple times, each value provided is returned on successive invocations of the method. It is also possible to mix `and_return` with `and_raise` in the same manner to alternate between returning a value and raising and exception on different method invocations. When combined with the `one_by_one` modifier, value is treated as a list of values to be returned in the order specified by successive calls to this method rather than a single list to be returned each time. Args: *values: Optional list of return values, defaults to `None` if not given. Returns: Self, i.e. can be chained with other Expectation methods. Examples: Provide return values for mocks: >>> flexmock(plane).should_receive("land").and_return("landed!").once() >>> plane.land() 'landed!' Match specific return values with spies: >>> flexmock(plane).should_call("passenger_count").and_return(3) >>> plane.passenger_count() 3 """ if not values: value = None elif len(values) == 1: value = values[0] else: value = values if not self._callable: _setattr(self._mock, str(self._name), value) return self return_values = self._return_values if not self._one_by_one: value = ReturnValue(value) return_values.append(value) else: try: return_values.extend([ReturnValue(v) for v in value]) # type: ignore except TypeError: return_values.append(ReturnValue(value)) return self def times(self, number: int) -> "Expectation": """Number of times this expectation's method is expected to be called. There are also 3 aliases for the `times()` method: - `once()` -> `times(1)` - `twice()` -> `times(2)` - `never()` -> `times(0)` Args: number: Expected call count. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("fly").times(1) >>> plane.fly() >>> flexmock(plane).should_call("land").times(2) >>> plane.land() >>> plane.land() """ if not self._callable: self.__raise(FlexmockError, "can't use times() with attribute stubs") expected_calls = self._expected_calls modifier = self._modifier expected_calls[modifier] = number return self def once(self) -> "Expectation": """Expect expectation's method to be called once. Alias for `times(1)`. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("land").once() >>> plane.land() """ self._called_deprecated_property = False return self.times(1) def twice(self) -> "Expectation": """Expect expectation's method to be called twice. Alias for `times(2)`. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("fly").twice() >>> plane.fly() >>> plane.fly() """ self._called_deprecated_property = False return self.times(2) def never(self) -> "Expectation": """Expect expectation's method to never be called. Alias for `times(0)`. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("crash").never() >>> plane.crash() Traceback (most recent call last): ... flexmock.exceptions.MethodCallError: crash() expected to be called... """ self._called_deprecated_property = False return self.times(0) def one_by_one(self) -> "Expectation": """Modifies the return value to be treated as a list of return values. Each value in the list is returned on successive invocations of the method. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("pilot").and_return("pilot1", "pilot2").one_by_one() >>> plane.pilot() 'pilot1' >>> plane.pilot() 'pilot2' """ if not self._callable: self.__raise(FlexmockError, "can't use one_by_one() with attribute stubs") if not self._one_by_one: self._one_by_one = True return_values = self._return_values saved_values = return_values[:] self._return_values = return_values = [] for value in saved_values: try: for val in value.value: # type: ignore return_values.append(ReturnValue(val)) except TypeError: return_values.append(value) return self def at_least(self) -> "Expectation": """Modifies the associated `times()` expectation. When given, an exception will only be raised if the method is called less than `times()` specified. Does nothing if `times()` is not given. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("fly").at_least().once() >>> plane.fly("east") """ if not self._callable: self.__raise(FlexmockError, "can't use at_least() with attribute stubs") expected_calls = self._expected_calls modifier = self._modifier if expected_calls[AT_LEAST] is not None or modifier == AT_LEAST: self.__raise(FlexmockError, "cannot use at_least modifier twice") if modifier == AT_MOST and expected_calls[AT_MOST] is None: self.__raise(FlexmockError, "cannot use at_least with at_most unset") self._modifier = AT_LEAST return self def at_most(self) -> "Expectation": """Modifies the associated `times()` expectation. When given, an exception will only be raised if the method is called more than `times()` specified. Does nothing if `times()` is not given. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("land").at_most().once() >>> plane.land() >>> plane.land() Traceback (most recent call last): ... flexmock.exceptions.MethodCallError: land() expected to be called at most... """ if not self._callable: self.__raise(FlexmockError, "can't use at_most() with attribute stubs") expected_calls = self._expected_calls modifier = self._modifier if expected_calls[AT_MOST] is not None or modifier == AT_MOST: self.__raise(FlexmockError, "cannot use at_most modifier twice") if modifier == AT_LEAST and expected_calls[AT_LEAST] is None: self.__raise(FlexmockError, "cannot use at_most with at_least unset") self._modifier = AT_MOST return self def ordered(self) -> "Expectation": """Makes the expectation respect the order of `should_receive` statements. An exception will be raised if methods are called out of order, determined by order of `should_receive` calls in the test. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("fly").with_args("east").ordered() >>> flexmock(plane).should_receive("fly").with_args("west").ordered() >>> plane.fly("west") Traceback (most recent call last): ... flexmock.exceptions.CallOrderError: fly("west") called before... """ if not self._callable: self.__raise(FlexmockError, "can't use ordered() with attribute stubs") self._ordered = True FlexmockContainer.ordered.append(self) return self def when(self, func: Callable[..., Any]) -> "Expectation": """Sets an outside resource to be checked when asserting if a method should be called. Args: func: Function that indicates if the mocked or spied method should have been called. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("land").when(lambda: plane.is_flying) >>> plane.is_flying True >>> plane.land() >>> plane.is_flying = False >>> plane.land() Traceback (most recent call last): ... flexmock.exceptions.StateError: land expected to be called when... """ if not self._callable: self.__raise(FlexmockError, "can't use when() with attribute stubs") if not hasattr(func, "__call__"): self.__raise(FlexmockError, "when() parameter must be callable") self._runnable = func return self def and_raise(self, exception: Type[BaseException], *args: Any, **kwargs: Any) -> "Expectation": """Specifies the exception to be raised when this expectation is met. Args: exception: Exception class. *args: Positional arguments to pass to the exception. **kwargs: Keyword arguments to pass to the exception. Returns: Self, i.e. can be chained with other Expectation methods. Examples: Make a mocked method raise an exception instead of returning a value: >>> flexmock(plane).should_receive("fly").and_raise(BadWeatherException) >>> plane.fly() Traceback (most recent call last): ... BadWeatherException Make a spy to verify that a specific exception is raised: >>> flexmock(plane).should_call("repair").and_raise(RuntimeError, "err msg") """ if not self._callable: self.__raise(FlexmockError, "can't use and_raise() with attribute stubs") if inspect.isclass(exception): try: exception(*args, **kwargs) except TypeError: self.__raise( FlexmockError, f"can't initialize {exception} with the given arguments" ) kargs = {"kargs": args, "kwargs": kwargs} return_values = self._return_values return_values.append(ReturnValue(raises=exception, value=kargs)) return self def replace_with(self, function: Callable[..., Any]) -> "Expectation": """Gives a function to run instead of the mocked out one. Args: function: A callable that is used to replace the original function. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("set_speed").replace_with(lambda x: x == 5) >>> plane.set_speed(5) True >>> plane.set_speed(4) False """ if not self._callable: self.__raise(FlexmockError, "can't use replace_with() with attribute/property stubs") replace_with = self._replace_with original = self.__dict__.get("_original") if replace_with: self.__raise(FlexmockError, "replace_with cannot be specified twice") if function == original: self._pass_thru = True self._replace_with = function return self def and_yield(self, *args: Any) -> "Expectation": """Specifies the list of items to be yielded on successive method calls. In effect, the mocked object becomes a generator. Args: *args: Items to be yielded on successive method calls. Returns: Self, i.e. can be chained with other Expectation methods. Examples: >>> flexmock(plane).should_receive("flight_log").and_yield("fly", "land") >>> log = plane.flight_log() >>> next(log) 'fly' >>> next(log) 'land' """ if not self._callable: self.__raise(FlexmockError, "can't use and_yield() with attribute stubs") return self.and_return(iter(args)) def _verify(self, final: bool = True) -> None: """Verify that this expectation has been met. Args: final: True if no further calls to this method expected (skip checking at_least expectations when False). Raises: MethodCallError Exception """ failed, message = self._verify_number_of_calls(final) if failed and not self._verified: self._verified = True self.__raise( MethodCallError, ( f"{_format_args(str(self._name), self._args)} expected to be called " f"{message}, called {self._times_called} " f"{'time' if self._times_called == 1 else 'times'}" ), ) def _verify_number_of_calls(self, final: bool) -> Tuple[bool, str]: if self._called_deprecated_property: raise FlexmockError( "Calling once, twice, never, or mock without parentheses has been deprecated" ) failed = False message = "" called_exactly = self._expected_calls[EXACTLY] called_at_least = self._expected_calls[AT_LEAST] called_at_most = self._expected_calls[AT_MOST] times_called = self._times_called if called_exactly is not None: message = f"exactly {called_exactly}" if final: if times_called != called_exactly: failed = True else: if times_called > called_exactly: failed = True message += " time" if called_exactly == 1 else " times" else: if final and called_at_least is not None: message = f"at least {called_at_least}" if times_called < called_at_least: failed = True message += " time" if called_at_least == 1 else " times" if called_at_most is not None: if message: message += " and " message += f"at most {called_at_most}" if times_called > called_at_most: failed = True message += " time" if called_at_most == 1 else " times" return failed, message def _reset(self) -> None: """Returns the methods overriden by this expectation to their originals.""" _mock = self._mock if not isinstance(_mock, Mock): original = self.__dict__.get("_original") if original: # name may be unicode but pypy demands dict keys to be str name = str(self._name) if hasattr(_mock, "__dict__") and name in _mock.__dict__ and self._local_override: delattr(_mock, name) elif ( hasattr(_mock, "__dict__") and name in _mock.__dict__ and isinstance(_mock.__dict__, dict) ): _mock.__dict__[name] = original else: setattr(_mock, name, original) del self class FlexmockContainer: """Holds global hash of object/expectation mappings.""" flexmock_objects: Dict[Mock, List[Expectation]] = {} properties: Dict[Any, List[str]] = {} ordered: List[Expectation] = [] last: Optional[Expectation] = None @classmethod def reset(cls) -> None: """Reset flexmock state.""" cls.ordered = [] cls.last = None cls.flexmock_objects = {} cls.properties = {} @classmethod def get_flexmock_expectation( cls, obj: Mock, name: str, args: Optional[Any] = None ) -> Optional[Expectation]: """Retrieves an existing matching expectation.""" if args is None: args = {"kargs": (), "kwargs": {}} if not isinstance(args, dict): args = {"kargs": args, "kwargs": {}} if not isinstance(args["kargs"], tuple): args["kargs"] = (args["kargs"],) found = None for expectation in reversed(cls.flexmock_objects[obj]): if expectation._name == name and expectation._match_args(args): if expectation in cls.ordered or not expectation._ordered and not found: found = expectation if found and found._ordered: cls._verify_call_order(found, args) return found @classmethod def _verify_call_order(cls, expectation: Expectation, args: Dict[str, Any]) -> None: next_method = cls.ordered.pop(0) cls.last = next_method if expectation is not next_method: raise CallOrderError( f"{_format_args(str(expectation._name), args)} called before " f"{_format_args(str(next_method._name), next_method._args)}" ) @classmethod def add_expectation(cls, obj: Mock, expectation: Expectation) -> None: """Add expectation.""" if obj in cls.flexmock_objects: cls.flexmock_objects[obj].append(expectation) else: cls.flexmock_objects[obj] = [expectation] @classmethod def get_expectations_with_name(cls, obj: Mock, name: str) -> List[Expectation]: """Get all expectations for given name.""" return [x for x in FlexmockContainer.flexmock_objects.get(obj, []) if x._name == name] @classmethod def add_teardown_property(cls, obj: Any, name: str) -> None: """Add teardown property.""" if obj in cls.properties: cls.properties[obj].append(name) else: cls.properties[obj] = [name] @classmethod def teardown_properties(cls) -> None: """Teardown properties.""" for obj, names in cls.properties.items(): for name in names: delattr(obj, name) def flexmock(spec: Optional[Any] = None, **kwargs: Any) -> Mock: """Main entry point into the flexmock API. This function is used to either generate a new fake object or take an existing object (or class or module) and use it as a basis for a partial mock. In case of a partial mock, the passed in object is modified to support basic Mock class functionality making it unnecessary to make successive `flexmock()` calls on the same objects to generate new expectations. It is safe to call `flexmock()` on the same object again, flexmock will detect when an object has already been partially mocked and return it each time. Args: spec: Object, class, or module to mock. **kwargs: Method or return value pairs to attach to the object. Returns: Mock object if no spec is provided. Otherwise return the spec object. Examples: >>> mock = flexmock(Plane) >>> mock.should_receive("fly") """ if spec is not None: return _create_partial_mock(spec, **kwargs) # use this intermediate class to attach properties klass = type("MockClass", (Mock,), {}) return klass(**kwargs) # type: ignore def _arg_to_str(arg: Any) -> str: if isinstance(arg, RE_TYPE): return f"/{arg.pattern}/" if isinstance(arg, str): return f'"{arg}"' return f"{arg}" def _format_args(name: str, arguments: Optional[Dict[str, Any]]) -> str: if arguments is None: arguments = {"kargs": (), "kwargs": {}} kargs = ", ".join(_arg_to_str(arg) for arg in arguments["kargs"]) kwargs = ", ".join(f"{k}={_arg_to_str(v)}" for k, v in arguments["kwargs"].items()) if kargs and kwargs: args = f"{kargs}, {kwargs}" else: args = f"{kargs}{kwargs}" return f"{name}({args})" def _create_partial_mock(obj_or_class: Any, **kwargs: Any) -> Mock: """Create partial mock.""" matches = [x for x in FlexmockContainer.flexmock_objects if x._object is obj_or_class] if matches: mock = matches[0] else: mock = Mock() mock._object = obj_or_class for name, return_value in kwargs.items(): if hasattr(return_value, "__call__"): mock.should_receive(name).replace_with(return_value) else: mock.should_receive(name).and_return(return_value) if not matches: FlexmockContainer.add_expectation(mock, Expectation(obj_or_class)) if _attach_flexmock_methods(mock, Mock, obj_or_class) and not inspect.isclass(mock._object): mock = mock._object return mock def _attach_flexmock_methods(mock: Mock, flexmock_class: Type[Mock], obj: Any) -> bool: try: for attr in UPDATED_ATTRS: if hasattr(obj, attr): if getattr(obj, attr).__code__ is not getattr(flexmock_class, attr).__code__: return False for attr in UPDATED_ATTRS: _setattr(obj, attr, getattr(mock, attr)) except TypeError as exc: raise MockBuiltinError( "Python does not allow you to mock builtin objects or modules. " "Consider wrapping it in a class you can mock instead" ) from exc except AttributeError as exc: raise MockBuiltinError( "Python does not allow you to mock instances of builtin objects. " "Consider wrapping it in a class you can mock instead" ) from exc return True def _arguments_match(arg: Any, expected_arg: Any) -> bool: if expected_arg == arg: return True if inspect.isclass(expected_arg) and isinstance(arg, expected_arg): return True if isinstance(expected_arg, RE_TYPE) and expected_arg.search(arg): return True return False def _setattr(obj: Any, name: str, value: Any) -> bool: """Ensure we use local __dict__ where possible.""" local_override = False if hasattr(obj, "__dict__") and isinstance(obj.__dict__, dict): if name not in obj.__dict__: # Overriding attribute locally on an instance. local_override = True obj.__dict__[name] = value else: if inspect.isclass(obj) and not vars(obj).get(name): # Overriding derived attribute locally on a child class. local_override = True setattr(obj, name, value) return local_override def _isproperty(obj: Any, name: str) -> bool: if isinstance(obj, Mock): return False if not inspect.isclass(obj) and hasattr(obj, "__dict__") and name not in obj.__dict__: attr = getattr(obj.__class__, name) if isinstance(attr, property): return True elif inspect.isclass(obj): attr = getattr(obj, name) if isinstance(attr, property): return True return False def _is_class_method(method: Callable[..., Any], name: str) -> bool: """Check if a method is a classmethod. This function checks all the classes in the class method resolution in order to get the correct result for derived methods as well. """ bound_to = getattr(method, "__self__", None) if not inspect.isclass(bound_to): return False for cls in inspect.getmro(bound_to): descriptor = vars(cls).get(name) if descriptor is not None: return isinstance(descriptor, classmethod) return False def _is_static_method(obj: Any, name: str) -> bool: try: return isinstance(inspect.getattr_static(obj, name), staticmethod) except AttributeError: # AttributeError is raised when mocking a proxied object if hasattr(obj, "__mro__"): for cls in inspect.getmro(obj): descriptor = vars(cls).get(name) if descriptor is not None: return isinstance(descriptor, staticmethod) return False ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1641292052.891851 flexmock-0.11.3/src/flexmock/_integrations.py0000644000000000000000000001564400000000000016123 0ustar00"""Flexmock test runner integrations.""" # pylint: disable=import-outside-toplevel, import-error import sys import unittest from contextlib import suppress from functools import wraps from typing import Any, Type from flexmock._api import flexmock_teardown def _patch_test_result(klass: Type[Any]) -> None: """Patches flexmock into any class that inherits unittest.TestResult. This seems to work well for majority of test runners. In the case of nose it's not even necessary as it doesn't override unittest.TestResults's addSuccess and addFailure methods so simply patching unittest works out of the box for nose. For those that do inherit from unittest.TestResult and override its stopTest and addSuccess methods, patching is pretty straightforward (numerous examples below). The reason we don't simply patch unittest's parent TestResult class is stopTest and addSuccess in the child classes tend to add messages into the output that we want to override in case flexmock generates its own failures. Args: klass: the class whose stopTest method needs to be decorated. """ # pylint: disable=invalid-name _patch_stop_test(klass) _patch_add_success(klass) def _patch_stop_test(klass: Type[unittest.TextTestResult]) -> None: """Patch TextTestResult class stopTest method and add call to flexmock teardown. If the test failed already before flexmock teardown, nothing is done. However if the test was successful before flexmock teardown and flexmock assertions fail, flexmock updates the test result to failed by calling addFailure method. Args: klass: the class whose stopTest method needs to be decorated. """ saved_add_success = klass.addSuccess saved_stop_test = klass.stopTest @wraps(saved_stop_test) def decorated(self: unittest.TextTestResult, test: unittest.TestCase) -> None: if saved_stop_test.__code__ is not decorated.__code__: # if parent class was for some reason patched, avoid calling # flexmock_teardown() twice and delegate up the class hierarchy # this doesn't help if there is a gap and only the parent's # parent class was patched, but should cover most screw-ups try: flexmock_teardown() saved_add_success(self, test) except Exception: if hasattr(self, "_pre_flexmock_success"): self.addFailure(test, sys.exc_info()) if hasattr(self, "_pre_flexmock_success"): del self._pre_flexmock_success # type: ignore return saved_stop_test(self, test) if klass.stopTest is not decorated: klass.stopTest = decorated # type: ignore def _patch_add_success(klass: Type[unittest.TextTestResult]) -> None: """Patch the addSuccess method of the TextTestResult class. TextTestResult addSuccess method is replaced and the original addSuccess method is called after flexmock teardown patched stopTest method. An attribute is set in the replaced addSuccess method to indicate if the test was successful before flexmock teardown was called. Args: klass: the class whose addSuccess method needs to be decorated. """ @wraps(klass.addSuccess) def decorated(self: unittest.TextTestResult, _test: unittest.TestCase, **_kwargs: Any) -> None: self._pre_flexmock_success = True # type: ignore if klass.addSuccess is not decorated: klass.addSuccess = decorated # type: ignore # Hook flexmock into Pytest. # Pytest is a Python test framework: # https://github.com/pytest-dev/pytest with suppress(ImportError): from _pytest import runner saved_pytest = runner.call_runtest_hook @wraps(saved_pytest) def call_runtest_hook( item: Any, when: str, **kwargs: Any, ) -> runner.CallInfo: """Call the teardown at the end of the tests. Args: item: The runner when: The moment this runs kwargs: additional arguments Returns: The teardown function """ ret = saved_pytest(item, when, **kwargs) # type: ignore if when != "call" and ret.excinfo is None: return ret teardown = runner.CallInfo.from_call(flexmock_teardown, when=when) # type: ignore if hasattr(teardown, "duration"): # CallInfo.duration only available in Pytest 6+ teardown.duration = ret.duration if ret.excinfo is not None: teardown.excinfo = ret.excinfo return teardown runner.call_runtest_hook = call_runtest_hook # Hook flexmock into doctest. with suppress(ImportError): from doctest import DocTestRunner, TestResults saved_doctest = DocTestRunner.run @wraps(saved_doctest) def run( *args: Any, **kwargs: Any, ) -> TestResults: """Call the teardown at the end of the tests. Args: args: the arguments passed to the runner kwargs: the keyword arguments passed to the runner Returns: The test results """ try: return saved_doctest(*args, **kwargs) finally: flexmock_teardown() DocTestRunner.run = run # type: ignore # Hook flexmock into unittest. # only valid TestResult class for unittest is TextTestResult _patch_test_result(unittest.TextTestResult) # Hook into Teamcity unittests. # This allows flexmock to be used within PyCharm. with suppress(ImportError): from teamcity.unittestpy import TeamcityTestResult _patch_test_result(TeamcityTestResult) # Hook into teststools. # testtools is a set of extensions to the Python standard library's unit testing framework: # https://github.com/testing-cabal/testtools with suppress(ImportError): from testtools import testresult _patch_test_result(testresult.TestResult) # Hook into Zope testrunner. # Zope is an open-source web application server: # https://github.com/zopefoundation/Zope with suppress(ImportError): from zope import testrunner # pylint: disable=no-name-in-module try: _patch_test_result(testrunner.runner.TestResult) except AttributeError: # testrunner.runner is only available when tests are executed with zope.testrunner pass # Hook into subunit. # Subunit is a test reporting and controlling protocol. # https://github.com/testing-cabal/subunit with suppress(ImportError): import subunit _patch_test_result(subunit.TestProtocolClient) _patch_test_result(subunit.test_results.TestResultDecorator) # Hook into twisted. # Twisted is an event-based framework for internet applications: # https://github.com/twisted/twisted with suppress(ImportError): from twisted.trial import reporter _patch_test_result(reporter.MinimalReporter) _patch_test_result(reporter.TextReporter) _patch_test_result(reporter.VerboseTextReporter) _patch_test_result(reporter.TreeReporter) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525627.2714567 flexmock-0.11.3/src/flexmock/exceptions.py0000644000000000000000000000106300000000000015425 0ustar00"""Flexmock exceptions.""" class FlexmockError(Exception): """FlexmockError""" class MockBuiltinError(Exception): """MockBuiltinError""" class MethodSignatureError(FlexmockError): """MethodSignatureError""" class ExceptionClassError(FlexmockError): """ExceptionClassError""" class ExceptionMessageError(FlexmockError): """ExceptionMessageError""" class StateError(FlexmockError): """StateError""" class MethodCallError(FlexmockError): """MethodCallError""" class CallOrderError(FlexmockError): """CallOrderError""" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1642036081.0123103 flexmock-0.11.3/src/flexmock/py.typed0000644000000000000000000000000000000000000014357 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525627.2714567 flexmock-0.11.3/tests/__init__.py0000644000000000000000000000000000000000000013534 0ustar00././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/__init__.py0000644000000000000000000000163300000000000015367 0ustar00"""Tests for flexmock. Tests under this module should not depend on any test runner. """ from .arg_matching import ArgumentMatchingTestCase from .call_count import CallCountTestCase from .common import CommonTestCase from .conditional import ConditionalAssertionsTestCase from .derived import DerivedTestCase from .mocking import MockingTestCase from .ordered import OrderedTestCase from .proxied import ProxiedTestCase from .spying import SpyingTestCase from .stubbing import StubbingTestCase from .teardown import TeardownTestCase class FlexmockTestCase( ArgumentMatchingTestCase, CallCountTestCase, CommonTestCase, ConditionalAssertionsTestCase, DerivedTestCase, MockingTestCase, OrderedTestCase, ProxiedTestCase, SpyingTestCase, StubbingTestCase, TeardownTestCase, ): """This class should be imported by other test modules to run full flexmock test suite. """ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/arg_matching.py0000644000000000000000000002525000000000000016254 0ustar00"""Tests for argument matching.""" # pylint: disable=missing-docstring,no-self-use,no-member import re from flexmock import exceptions, flexmock from flexmock._api import flexmock_teardown from tests import some_module from tests.some_module import SomeClass from tests.utils import assert_raises class ArgumentMatchingTestCase: def test_arg_matching_works_with_regexp(self): class Foo: def method(self, arg1, arg2): pass instance = Foo() flexmock(instance).should_receive("method").with_args( re.compile("^arg1.*asdf$"), arg2=re.compile("f") ).and_return("mocked") assert instance.method("arg1somejunkasdf", arg2="aadsfdas") == "mocked" def test_arg_matching_with_regexp_fails_when_regexp_doesnt_match_karg(self): class Foo: def method(self, arg1, arg2): pass instance = Foo() flexmock(instance).should_receive("method").with_args( re.compile("^arg1.*asdf$"), arg2=re.compile("a") ).and_return("mocked") with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod("arg1somejunkasdfa", arg2="a")\n' " Expected call[1]:\tmethod(arg2=/a/, arg1=/^arg1.*asdf$/)" ), ): instance.method("arg1somejunkasdfa", arg2="a") def test_arg_matching_with_regexp_fails_when_regexp_doesnt_match_kwarg(self): class Foo: def method(self, arg1, arg2): pass instance = Foo() flexmock(instance).should_receive("method").with_args( re.compile("^arg1.*asdf$"), arg2=re.compile("a") ).and_return("mocked") with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod("arg1somejunkasdf", arg2="b")\n' " Expected call[1]:\tmethod(arg2=/a/, arg1=/^arg1.*asdf$/)" ), ): instance.method("arg1somejunkasdf", arg2="b") def test_module_level_function_with_kwargs(self): flexmock(some_module).should_receive("module_function").with_args(1, y="expected") with assert_raises( exceptions.FlexmockError, ( "Arguments for call module_function did not match expectations:\n" ' Received call:\tmodule_function(1, y="not expected")\n' ' Expected call[1]:\tmodule_function(y="expected", x=1)' ), ): some_module.module_function(1, y="not expected") def test_flexmock_should_match_types_on_multiple_arguments(self): class Foo: def method(self, arg1, arg2): pass instance = Foo() flexmock(instance).should_receive("method").with_args(str, int).and_return("ok") assert instance.method("some string", 12) == "ok" with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" " Received call:\tmethod(12, 32)\n" " Expected call[1]:\tmethod(arg1=, arg2=)" ), ): instance.method(12, 32) flexmock(instance).should_receive("method").with_args(str, int).and_return("ok") with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod(12, "some string")\n' " Expected call[1]:\tmethod(arg1=, arg2=)\n" " Expected call[2]:\tmethod(arg1=, arg2=)" ), ): instance.method(12, "some string") flexmock(instance).should_receive("method").with_args(str, int).and_return("ok") with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod("string", 12, 14)\n' " Expected call[1]:\tmethod(arg1=, arg2=)\n" " Expected call[2]:\tmethod(arg1=, arg2=)\n" " Expected call[3]:\tmethod(arg1=, arg2=)" ), ): instance.method("string", 12, 14) def test_flexmock_should_match_types_on_multiple_arguments_generic(self): class Foo: def method(self, a, b, c): # pylint: disable=invalid-name pass instance = Foo() flexmock(instance).should_receive("method").with_args(object, object, object).and_return( "ok" ) assert instance.method("some string", None, 12) == "ok" assert instance.method((1,), None, 12) == "ok" assert instance.method(12, 14, []) == "ok" assert instance.method("some string", "another one", False) == "ok" with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod("string", 12)\n' " Expected call[1]:\tmethod(a=, " "b=, c=)" ), ): instance.method("string", 12) # pylint: disable=no-value-for-parameter flexmock_teardown() flexmock(instance).should_receive("method").with_args(object, object, object).and_return( "ok" ) with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" ' Received call:\tmethod("string", 12, 13, 14)\n' " Expected call[1]:\tmethod(a=, " "b=, c=)" ), ): instance.method("string", 12, 13, 14) def test_flexmock_should_match_types_on_multiple_arguments_classes(self): class Foo: def method(self, a, b): # pylint: disable=invalid-name pass class Bar: pass foo_instance = Foo() bar_instance = Bar() flexmock(foo_instance).should_receive("method").with_args(object, Bar).and_return("ok") assert foo_instance.method("some string", bar_instance) == "ok" with assert_raises( exceptions.MethodSignatureError, re.compile( "Arguments for call method did not match expectations:\n" r' Received call:\tmethod\(.+\.\.Bar object at 0x.+>, "some string"\)\n' r" Expected call\[1\]:\tmethod\(a=, b=\.Bar'>\)" ), ): foo_instance.method(bar_instance, "some string") flexmock_teardown() flexmock(foo_instance).should_receive("method").with_args(object, Bar).and_return("ok") with assert_raises( exceptions.MethodSignatureError, re.compile( "Arguments for call method did not match expectations:\n" r' Received call:\tmethod\(12, "some string"\)\n' r" Expected call\[1\]:\tmethod\(a=, b=\.Bar'>\)" ), ): foo_instance.method(12, "some string") def test_flexmock_should_match_keyword_arguments(self): class Foo: def method(self, arg1, **kwargs): pass instance = Foo() flexmock(instance).should_receive("method").with_args(1, arg3=3, arg2=2).twice() instance.method(1, arg2=2, arg3=3) instance.method(1, arg3=3, arg2=2) flexmock_teardown() flexmock(instance).should_receive("method").with_args(1, arg3=3, arg2=2) with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" " Received call:\tmethod(arg2=2, arg3=3)\n" " Expected call[1]:\tmethod(arg3=3, arg2=2, arg1=1)" ), ): instance.method(arg2=2, arg3=3) # pylint: disable=no-value-for-parameter flexmock_teardown() flexmock(instance).should_receive("method").with_args(1, arg3=3, arg2=2) with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" " Received call:\tmethod(1, arg2=2, arg3=4)\n" " Expected call[1]:\tmethod(arg3=3, arg2=2, arg1=1)" ), ): instance.method(1, arg2=2, arg3=4) flexmock_teardown() flexmock(instance).should_receive("method").with_args(1, arg3=3, arg2=2) with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method did not match expectations:\n" " Received call:\tmethod(1)\n" " Expected call[1]:\tmethod(arg3=3, arg2=2, arg1=1)" ), ): instance.method(1) def test_flexmock_should_call_should_match_keyword_arguments(self): class Foo: def method(self, arg1, arg2=None, arg3=None): return f"{arg1}{arg2}{arg3}" instance = Foo() flexmock(instance).should_call("method").with_args(1, arg3=3, arg2=2).once() assert instance.method(1, arg2=2, arg3=3) == "123" def test_with_args_with_instance_method(self): flexmock(SomeClass).should_receive("instance_method_with_args").with_args("red").once() flexmock(SomeClass).should_receive("instance_method_with_args").with_args("blue").once() instance = SomeClass() instance.instance_method_with_args("red") instance.instance_method_with_args("blue") def test_with_args_with_class_method(self): flexmock(SomeClass).should_receive("class_method_with_args").with_args("red").once() flexmock(SomeClass).should_receive("class_method_with_args").with_args("blue").once() SomeClass.class_method_with_args("red") SomeClass.class_method_with_args("blue") def test_with_args_with_static_method(self): flexmock(SomeClass).should_receive("static_method_with_args").with_args("red").once() flexmock(SomeClass).should_receive("static_method_with_args").with_args("blue").once() SomeClass.static_method_with_args("red") SomeClass.static_method_with_args("blue") ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/call_count.py0000644000000000000000000000513500000000000015754 0ustar00"""Tests for call count modifiers.""" # pylint: disable=missing-docstring,no-self-use,no-member from flexmock import exceptions, flexmock from flexmock._api import flexmock_teardown from tests.utils import assert_raises class CallCountTestCase: def test_support_at_least_and_at_most_together(self): class Foo: def method(self): pass instance = Foo() flexmock(instance).should_call("method").at_least().once().at_most().twice() with assert_raises( exceptions.MethodCallError, "method() expected to be called at least 1 time and at most 2 times, called 0 times", ): flexmock_teardown() flexmock(instance).should_call("method").at_least().once().at_most().twice() instance.method() instance.method() with assert_raises( exceptions.MethodCallError, "method() expected to be called at most 2 times, called 3 times", ): instance.method() flexmock(instance).should_call("method").at_least().once().at_most().twice() instance.method() flexmock_teardown() flexmock(instance).should_call("method").at_least().once().at_most().twice() instance.method() instance.method() flexmock_teardown() def test_at_least_cannot_be_used_twice(self): class Foo: def method(self): pass expectation = flexmock(Foo).should_receive("method") with assert_raises(exceptions.FlexmockError, "cannot use at_least modifier twice"): expectation.at_least().at_least() def test_at_most_cannot_be_used_twice(self): class Foo: def method(self): pass expectation = flexmock(Foo).should_receive("method") with assert_raises(exceptions.FlexmockError, "cannot use at_most modifier twice"): expectation.at_most().at_most() def test_at_least_cannot_be_specified_until_at_most_is_set(self): class Foo: def method(self): pass expectation = flexmock(Foo).should_receive("method") with assert_raises(exceptions.FlexmockError, "cannot use at_most with at_least unset"): expectation.at_least().at_most() def test_at_most_cannot_be_specified_until_at_least_is_set(self): class Foo: def method(self): pass expectation = flexmock(Foo).should_receive("method") with assert_raises(exceptions.FlexmockError, "cannot use at_least with at_most unset"): expectation.at_most().at_least() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/common.py0000644000000000000000000001602000000000000015114 0ustar00"""Flexmock tests that are not related to any particular feature.""" # pylint: disable=missing-docstring,no-self-use from flexmock import Mock, flexmock from flexmock._api import ( ReturnValue, _format_args, _is_class_method, _is_static_method, _isproperty, ) from tests.proxy import Proxy from tests.some_module import DerivedClass, SomeClass class CommonTestCase: def test_return_value_to_str(self): r_val = ReturnValue(value=1) assert str(r_val) == "1" r_val = ReturnValue(value=(1,)) assert str(r_val) == "1" r_val = ReturnValue(value=(1, 2)) assert str(r_val) == "(1, 2)" r_val = ReturnValue(value=1, raises=RuntimeError) assert str(r_val) == "(1)" def test_is_class_method(self): assert _is_class_method(SomeClass.class_method, "class_method") is True assert _is_class_method(SomeClass.static_method, "static_method") is False assert _is_class_method(SomeClass.instance_method, "instance_method") is False # Method names do no match assert _is_class_method(SomeClass.class_method, "other_method") is False some_class = SomeClass() assert _is_class_method(some_class.class_method, "class_method") is True assert _is_class_method(some_class.static_method, "static_method") is False assert _is_class_method(some_class.instance_method, "instance_method") is False assert _is_class_method(DerivedClass.class_method, "class_method") is True assert _is_class_method(DerivedClass.static_method, "static_method") is False assert _is_class_method(DerivedClass.instance_method, "instance_method") is False derived_class = DerivedClass() assert _is_class_method(derived_class.class_method, "class_method") is True assert _is_class_method(derived_class.static_method, "static_method") is False assert _is_class_method(derived_class.instance_method, "instance_method") is False def test_is_class_method_proxied(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) assert _is_class_method(SomeClassProxy.class_method, "class_method") is True assert _is_class_method(SomeClassProxy.static_method, "static_method") is False assert _is_class_method(SomeClassProxy.instance_method, "instance_method") is False some_class = SomeClassProxy() assert _is_class_method(some_class.class_method, "class_method") is True assert _is_class_method(some_class.static_method, "static_method") is False assert _is_class_method(some_class.instance_method, "instance_method") is False DerivedClassProxy = Proxy(DerivedClass) assert _is_class_method(DerivedClassProxy.class_method, "class_method") is True assert _is_class_method(DerivedClassProxy.static_method, "static_method") is False assert _is_class_method(DerivedClassProxy.instance_method, "instance_method") is False derived_class = DerivedClassProxy() assert _is_class_method(derived_class.class_method, "class_method") is True assert _is_class_method(derived_class.static_method, "static_method") is False assert _is_class_method(derived_class.instance_method, "instance_method") is False def test_is_static_method(self): assert _is_static_method(SomeClass, "class_method") is False assert _is_static_method(SomeClass, "static_method") is True assert _is_static_method(SomeClass, "instance_method") is False some_class = SomeClass() assert _is_static_method(some_class, "class_method") is False assert _is_static_method(some_class, "static_method") is True assert _is_static_method(some_class, "instance_method") is False assert _is_static_method(DerivedClass, "class_method") is False assert _is_static_method(DerivedClass, "static_method") is True assert _is_static_method(DerivedClass, "instance_method") is False derived_class = DerivedClass() assert _is_static_method(derived_class, "class_method") is False assert _is_static_method(derived_class, "static_method") is True assert _is_static_method(derived_class, "instance_method") is False def test_is_static_method_proxied(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) assert _is_static_method(SomeClassProxy, "class_method") is False assert _is_static_method(SomeClassProxy, "static_method") is True assert _is_static_method(SomeClassProxy, "instance_method") is False some_class = SomeClassProxy() assert _is_static_method(some_class, "class_method") is False assert _is_static_method(some_class, "static_method") is True assert _is_static_method(some_class, "instance_method") is False DerivedClassProxy = Proxy(DerivedClass) assert _is_static_method(DerivedClassProxy, "class_method") is False assert _is_static_method(DerivedClassProxy, "static_method") is True assert _is_static_method(DerivedClassProxy, "instance_method") is False derived_class = DerivedClassProxy() assert _is_static_method(derived_class, "class_method") is False assert _is_static_method(derived_class, "static_method") is True assert _is_static_method(derived_class, "instance_method") is False def test_isproperty(self): class BaseClass: @property def method1(self): pass def method2(self): pass class ChildClass(BaseClass): pass base_instance = BaseClass() child_instance = ChildClass() assert _isproperty(base_instance, "method1") is True assert _isproperty(base_instance, "method2") is False assert _isproperty(BaseClass, "method1") is True assert _isproperty(BaseClass, "method2") is False assert _isproperty(child_instance, "method1") is True assert _isproperty(child_instance, "method2") is False assert _isproperty(ChildClass, "method1") is True assert _isproperty(ChildClass, "method2") is False assert _isproperty(Mock(), "method2") is False def test_format_args_supports_tuples(self): formatted = _format_args("method", {"kargs": ((1, 2),), "kwargs": {}}) assert formatted == "method((1, 2))" def test_flexmock_should_not_explode_on_unicode_formatting(self): formatted = _format_args("method", {"kargs": (chr(0x86C7),), "kwargs": {}}) assert formatted == 'method("蛇")' def test_return_value_should_not_explode_on_unicode_values(self): return_value = ReturnValue(chr(0x86C7)) assert f"{return_value}" == '"蛇"' return_value = ReturnValue((chr(0x86C7), chr(0x86C7))) assert f"{return_value}" == '("蛇", "蛇")' def test_flexmock_should_yield_self_when_iterated(self): class ClassNoIter: pass instance = flexmock(ClassNoIter) assert instance is list(instance)[0] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/conditional.py0000644000000000000000000000404600000000000016134 0ustar00"""Tests for conditional assertions.""" # pylint: disable=missing-docstring,no-self-use,no-member import functools from flexmock import exceptions, flexmock from tests.utils import assert_raises class ConditionalAssertionsTestCase: def test_state_machine(self): class Radio: def __init__(self): self.is_on = False self.volume = 0 def switch_on(self): self.is_on = True def switch_off(self): self.is_on = False def select_channel(self): return None def adjust_volume(self, num): self.volume = num radio = Radio() flexmock(radio) def radio_is_on(): return radio.is_on radio.should_receive("select_channel").once().when(lambda: radio.is_on) radio.should_call("adjust_volume").once().with_args(5).when(radio_is_on) with assert_raises( exceptions.StateError, "select_channel expected to be called when lambda: radio.is_on is True", ): radio.select_channel() with assert_raises( exceptions.StateError, "adjust_volume expected to be called when radio_is_on is True" ): radio.adjust_volume(5) radio.is_on = True radio.select_channel() radio.adjust_volume(5) def test_when_parameter_should_be_callable(self): with assert_raises(exceptions.FlexmockError, "when() parameter must be callable"): flexmock().should_receive("something").when(1) def test_flexmock_should_not_blow_up_with_builtin_in_when(self): # It is not possible to get source for builtins. Flexmock should handle # this gracefully. mock = flexmock() mock.should_receive("something").when(functools.partial(lambda: False)) with assert_raises( exceptions.StateError, "something expected to be called when condition is True" ): # Should not raise TypeError mock.something() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/derived.py0000644000000000000000000001465300000000000015260 0ustar00"""Tests for mocking and spying derived classes.""" # pylint: disable=missing-docstring,no-self-use,no-member from flexmock import exceptions, flexmock from tests.some_module import DerivedClass, SomeClass from tests.utils import assert_raises class DerivedTestCase: def test_mock_class_method_on_derived_class(self): flexmock(DerivedClass).should_receive("class_method").and_return(2).twice() assert DerivedClass().class_method() == 2 assert DerivedClass.class_method() == 2 def test_mock_class_method_on_derived_class_after_mocking_base_class(self): flexmock(SomeClass).should_receive("class_method").and_return(1).once() assert SomeClass.class_method() == 1 flexmock(DerivedClass).should_receive("class_method").and_return(2).twice() assert DerivedClass().class_method() == 2 assert DerivedClass.class_method() == 2 def test_mock_static_method_on_derived_class(self): flexmock(DerivedClass).should_receive("static_method").and_return(4).twice() assert DerivedClass().static_method() == 4 assert DerivedClass.static_method() == 4 def test_mock_static_method_on_derived_class_after_mocking_base_class(self): flexmock(SomeClass).should_receive("static_method").and_return(3).once() assert SomeClass.static_method() == 3 flexmock(DerivedClass).should_receive("static_method").and_return(4).twice() assert DerivedClass().static_method() == 4 assert DerivedClass.static_method() == 4 def test_mock_class_method_with_args_on_derived_class(self): flexmock(DerivedClass).should_receive("class_method_with_args").with_args(2).and_return( 3 ).twice() assert DerivedClass().class_method_with_args(2) == 3 assert DerivedClass.class_method_with_args(2) == 3 def test_mock_class_method_with_args_on_derived_class_after_mocking_base_class(self): flexmock(SomeClass).should_receive("class_method_with_args").with_args(1).and_return( 2 ).once() assert SomeClass.class_method_with_args(1) == 2 flexmock(DerivedClass).should_receive("class_method_with_args").with_args(2).and_return( 3 ).twice() assert DerivedClass().class_method_with_args(2) == 3 assert DerivedClass.class_method_with_args(2) == 3 def test_mock_static_method_with_args_on_derived_class(self): flexmock(DerivedClass).should_receive("static_method_with_args").with_args(4).and_return( 5 ).twice() assert DerivedClass().static_method_with_args(4) == 5 assert DerivedClass.static_method_with_args(4) == 5 def test_mock_static_method_with_args_on_derived_class_after_mocking_base_class(self): flexmock(SomeClass).should_receive("static_method_with_args").with_args(2).and_return( 3 ).once() assert SomeClass.static_method_with_args(2) == 3 flexmock(DerivedClass).should_receive("static_method_with_args").with_args(4).and_return( 5 ).twice() assert DerivedClass().static_method_with_args(4) == 5 assert DerivedClass.static_method_with_args(4) == 5 def test_spy_class_method_on_derived_class(self): flexmock(DerivedClass).should_call("class_method").and_return("class_method").twice() assert DerivedClass().class_method() == "class_method" assert DerivedClass.class_method() == "class_method" def test_spy_class_method_on_derived_class_after_spying_base_class(self): flexmock(SomeClass).should_call("class_method").and_return("class_method").times( 3 ) # TODO: Should be once #80 assert SomeClass.class_method() == "class_method" flexmock(DerivedClass).should_call("class_method").and_return("class_method").twice() assert DerivedClass().class_method() == "class_method" assert DerivedClass.class_method() == "class_method" def test_spy_static_method_on_derived_class(self): flexmock(DerivedClass).should_call("static_method").and_return("static_method").twice() assert DerivedClass().static_method() == "static_method" assert DerivedClass.static_method() == "static_method" def test_spy_static_method_on_derived_class_after_spying_base_class(self): flexmock(SomeClass).should_call("static_method").and_return("static_method").times( 3 ) # TODO: Should be once #80 assert SomeClass.static_method() == "static_method" flexmock(DerivedClass).should_call("static_method").and_return("static_method").twice() assert DerivedClass().static_method() == "static_method" assert DerivedClass.static_method() == "static_method" def test_spy_class_method_with_args_on_derived_class(self): flexmock(DerivedClass).should_call("class_method_with_args").with_args(2).and_return(2) assert DerivedClass().class_method_with_args(2) == 2 assert DerivedClass.class_method_with_args(2) == 2 @assert_raises( exceptions.MethodSignatureError, match=None ) # TODO: Should not raise exception #79 def test_spy_class_method_with_args_on_derived_class_after_spying_base_class(self): flexmock(SomeClass).should_call("class_method_with_args").with_args(1).and_return(1) assert SomeClass.class_method_with_args(1) == 1 flexmock(DerivedClass).should_call("class_method_with_args").with_args(2).and_return(2) assert DerivedClass().class_method_with_args(2) == 2 assert DerivedClass.class_method_with_args(2) == 2 def test_spy_static_method_with_args_on_derived_class(self): flexmock(DerivedClass).should_call("static_method_with_args").with_args(4).and_return( 4 ).twice() assert DerivedClass().static_method_with_args(4) == 4 assert DerivedClass.static_method_with_args(4) == 4 @assert_raises( exceptions.MethodSignatureError, match=None ) # TODO: Should not raise exception #79 def test_spy_static_method_with_args_on_derived_class_after_spying_base_class(self): flexmock(SomeClass).should_call("static_method_with_args").with_args(2).and_return(2).once() assert SomeClass.static_method_with_args(2) == 2 flexmock(DerivedClass).should_call("static_method_with_args").with_args(4).and_return( 4 ).once() # should be twice assert DerivedClass().static_method_with_args(4) == 4 assert DerivedClass.static_method_with_args(4) == 4 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/mocking.py0000644000000000000000000014343100000000000015262 0ustar00"""Tests for flexmock mocking feature.""" # pylint: disable=missing-docstring,no-self-use,no-member,too-many-lines import os import random import re import sys from flexmock import exceptions, flexmock from flexmock._api import AT_LEAST, AT_MOST, EXACTLY, FlexmockContainer, Mock, flexmock_teardown from tests import some_module from tests.utils import assert_raises class MockingTestCase: def test_print_expectation(self): mock = flexmock() expectation = mock.should_receive("foo") assert str(expectation) == "foo() -> ()" def test_flexmock_should_create_mock_object(self): mock = flexmock() assert isinstance(mock, Mock) def test_flexmock_should_create_mock_object_from_dict(self): mock = flexmock(foo="foo", bar="bar") assert mock.foo == "foo" assert mock.bar == "bar" def test_flexmock_should_add_expectations(self): mock = flexmock(name="temp") mock.should_receive("method_foo") assert "method_foo" in [x._name for x in FlexmockContainer.flexmock_objects[mock]] def test_flexmock_should_return_value(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar") mock.should_receive("method_bar").and_return("value_baz") assert mock.method_foo() == "value_bar" assert mock.method_bar() == "value_baz" def test_calling_deprecated_properties_should_raise_exception(self): error_msg = "Calling once, twice, never, or mock without parentheses has been deprecated" mock = flexmock() mock.should_receive("foo").once # pylint: disable=expression-not-assigned with assert_raises(exceptions.FlexmockError, error_msg): flexmock_teardown() mock.should_receive("foo").twice # pylint: disable=expression-not-assigned with assert_raises(exceptions.FlexmockError, error_msg): flexmock_teardown() mock.should_receive("foo").never # pylint: disable=expression-not-assigned with assert_raises(exceptions.FlexmockError, error_msg): flexmock_teardown() mock.should_receive("foo").mock # pylint: disable=expression-not-assigned with assert_raises(exceptions.FlexmockError, error_msg): flexmock_teardown() def test_type_flexmock_with_unicode_string_in_should_receive(self): class Foo: def method(self): return "bar" flexmock(Foo).should_receive("method").and_return("mocked_bar") instance = Foo() assert instance.method() == "mocked_bar" def test_flexmock_should_accept_shortcuts_for_creating_mock_object(self): mock = flexmock(attr1="value 1", attr2=lambda: "returning 2") assert mock.attr1 == "value 1" assert mock.attr2() == "returning 2" def test_flexmock_should_accept_shortcuts_for_creating_expectations(self): class Foo: def method1(self): pass def method2(self): pass instance = Foo() flexmock(instance, method1="returning 1", method2="returning 2") assert instance.method1() == "returning 1" assert instance.method2() == "returning 2" assert instance.method2() == "returning 2" def test_flexmock_expectations_returns_all(self): mock = flexmock(name="temp") assert mock not in FlexmockContainer.flexmock_objects mock.should_receive("method_foo") mock.should_receive("method_bar") assert len(FlexmockContainer.flexmock_objects[mock]) == 2 def test_flexmock_expectations_returns_named_expectation(self): mock = flexmock(name="temp") mock.should_receive("method_foo") assert FlexmockContainer.get_flexmock_expectation(mock, "method_foo")._name == "method_foo" def test_flexmock_expectations_returns_none_if_not_found(self): mock = flexmock(name="temp") mock.should_receive("method_foo") assert FlexmockContainer.get_flexmock_expectation(mock, "method_bar") is None def test_flexmock_should_check_parameters(self): mock = flexmock(name="temp") mock.should_receive("method_foo").with_args("bar").and_return(1) mock.should_receive("method_foo").with_args("baz").and_return(2) assert mock.method_foo("bar") == 1 assert mock.method_foo("baz") == 2 def test_flexmock_should_keep_track_of_calls(self): mock = flexmock(name="temp") mock.should_receive("method_foo").with_args("foo").and_return(0) mock.should_receive("method_foo").with_args("bar").and_return(1) mock.should_receive("method_foo").with_args("baz").and_return(2) mock.method_foo("bar") mock.method_foo("bar") mock.method_foo("baz") expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo", ("foo",)) assert expectation._times_called == 0 expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo", ("bar",)) assert expectation._times_called == 2 expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo", ("baz",)) assert expectation._times_called == 1 def test_flexmock_should_set_expectation_call_numbers(self): mock = flexmock(name="temp") mock.should_receive("method_foo").times(1) expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called exactly 1 time, called 0 times", ): expectation._verify() mock.method_foo() expectation._verify() def test_flexmock_should_check_raised_exceptions(self): mock = flexmock(name="temp") class FakeException(Exception): pass mock.should_receive("method_foo").and_raise(FakeException) with assert_raises(FakeException, ""): mock.method_foo() assert FlexmockContainer.get_flexmock_expectation(mock, "method_foo")._times_called == 1 def test_flexmock_should_check_raised_exceptions_instance_with_args(self): mock = flexmock(name="temp") class FakeException(Exception): def __init__(self, arg, arg2): # pylint: disable=super-init-not-called pass mock.should_receive("method_foo").and_raise(FakeException(1, arg2=2)) with assert_raises(FakeException, "1"): mock.method_foo() assert FlexmockContainer.get_flexmock_expectation(mock, "method_foo")._times_called == 1 def test_flexmock_should_check_raised_exceptions_class_with_args(self): mock = flexmock(name="temp") class FakeException(Exception): def __init__(self, arg, arg2): # pylint: disable=super-init-not-called pass mock.should_receive("method_foo").and_raise(FakeException, 1, arg2=2) with assert_raises(FakeException, "1"): mock.method_foo() assert FlexmockContainer.get_flexmock_expectation(mock, "method_foo")._times_called == 1 def test_flexmock_should_match_any_args_by_default(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("bar") mock.should_receive("method_foo").with_args("baz").and_return("baz") assert mock.method_foo() == "bar" assert mock.method_foo(1) == "bar" assert mock.method_foo("foo", "bar") == "bar" assert mock.method_foo("baz") == "baz" def test_flexmock_should_fail_to_match_exactly_no_args_when_calling_with_args(self): mock = flexmock() mock.should_receive("method_foo").with_args() with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method_foo did not match expectations:\n" ' Received call:\tmethod_foo("baz")\n' " Expected call[1]:\tmethod_foo()" ), ): mock.method_foo("baz") def test_flexmock_should_match_exactly_no_args(self): class Foo: def method(self): pass instance = Foo() flexmock(instance).should_receive("method").with_args().and_return("baz") assert instance.method() == "baz" def test_expectation_dot_mock_should_return_mock(self): mock = flexmock(name="temp") assert mock.should_receive("method_foo").mock() == mock def test_flexmock_should_create_partial_new_style_object_mock(self): class User: def __init__(self, name=None): self.name = name def get_name(self): return self.name def set_name(self, name): self.name = name user = User() flexmock(user) user.should_receive("get_name").and_return("john") user.set_name("mike") assert user.get_name() == "john" def test_flexmock_should_create_partial_old_style_object_mock(self): class User: def __init__(self, name=None): self.name = name def get_name(self): return self.name def set_name(self, name): self.name = name user = User() flexmock(user) user.should_receive("get_name").and_return("john") user.set_name("mike") assert user.get_name() == "john" def test_flexmock_should_create_partial_new_style_class_mock(self): class User: def __init__(self): pass def get_name(self): pass flexmock(User) User.should_receive("get_name").and_return("mike") user = User() assert user.get_name() == "mike" def test_flexmock_should_create_partial_old_style_class_mock(self): class User: def __init__(self): pass def get_name(self): pass flexmock(User) User.should_receive("get_name").and_return("mike") user = User() assert user.get_name() == "mike" def test_flexmock_should_match_expectations_against_builtin_classes(self): mock = flexmock(name="temp") mock.should_receive("method_foo").with_args(str).and_return("got a string") mock.should_receive("method_foo").with_args(int).and_return("got an int") assert mock.method_foo("string!") == "got a string" assert mock.method_foo(23) == "got an int" with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method_foo did not match expectations:\n" " Received call:\tmethod_foo(2.0)\n" " Expected call[1]:\tmethod_foo()\n" " Expected call[2]:\tmethod_foo()" ), ): mock.method_foo(2.0) def test_with_args_should_work_with_builtin_c_methods(self): flexmock(sys.stdout).should_call("write") # set fall-through flexmock(sys.stdout).should_receive("write").with_args("flexmock_builtin_test") sys.stdout.write("flexmock_builtin_test") def test_with_args_should_work_with_builtin_c_functions(self): mocked = flexmock(sys) mocked.should_receive("exit").with_args(1).once() mocked.exit(1) flexmock_teardown() flexmock(os).should_receive("remove").with_args("path").once() os.remove("path") def test_with_args_should_work_with_builtin_python_methods(self): flexmock(random).should_receive("randint").with_args(1, 10).once() random.randint(1, 10) def test_flexmock_should_match_expectations_against_user_defined_classes(self): mock = flexmock(name="temp") class Foo: pass mock.should_receive("method_foo").with_args(Foo).and_return("got a Foo") assert mock.method_foo(Foo()) == "got a Foo" with assert_raises( exceptions.MethodSignatureError, ( "Arguments for call method_foo did not match expectations:\n" " Received call:\tmethod_foo(1)\n" " Expected call[1]:\tmethod_foo(.Foo'>)" ), ): mock.method_foo(1) def test_flexmock_configures_global_mocks_dict(self): mock = flexmock(name="temp") assert mock not in FlexmockContainer.flexmock_objects mock.should_receive("method_foo") assert mock in FlexmockContainer.flexmock_objects assert len(FlexmockContainer.flexmock_objects[mock]) == 1 def test_flexmock_teardown_verifies_mocks(self): mock = flexmock(name="temp") mock.should_receive("verify_expectations").times(1) with assert_raises( exceptions.MethodCallError, "verify_expectations() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() def test_flexmock_teardown_does_not_verify_stubs(self): mock = flexmock(name="temp") mock.should_receive("verify_expectations") flexmock_teardown() def test_flexmock_preserves_stubbed_object_methods_between_tests(self): class User: def get_name(self): return "mike" user = User() flexmock(user).should_receive("get_name").and_return("john") assert user.get_name() == "john" flexmock_teardown() assert user.get_name() == "mike" def test_flexmock_preserves_stubbed_class_methods_between_tests(self): class User: def get_name(self): return "mike" user = User() flexmock(User).should_receive("get_name").and_return("john") assert user.get_name() == "john" flexmock_teardown() assert user.get_name() == "mike" def test_flexmock_removes_new_stubs_from_objects_after_tests(self): class User: def get_name(self): pass user = User() saved = user.get_name flexmock(user).should_receive("get_name").and_return("john") assert saved != user.get_name assert user.get_name() == "john" flexmock_teardown() assert user.get_name == saved def test_flexmock_removes_new_stubs_from_classes_after_tests(self): class User: def get_name(self): pass user = User() saved = user.get_name flexmock(User).should_receive("get_name").and_return("john") assert saved != user.get_name assert user.get_name() == "john" flexmock_teardown() assert user.get_name == saved def test_flexmock_removes_stubs_from_multiple_objects_on_teardown(self): class User: def get_name(self): pass class Group: def get_name(self): pass user = User() group = Group() saved1 = user.get_name saved2 = group.get_name flexmock(user).should_receive("get_name").and_return("john").once() flexmock(group).should_receive("get_name").and_return("john").once() assert saved1 != user.get_name assert saved2 != group.get_name assert user.get_name() == "john" assert group.get_name() == "john" flexmock_teardown() assert user.get_name == saved1 assert group.get_name == saved2 def test_flexmock_removes_stubs_from_multiple_classes_on_teardown(self): class User: def get_name(self): pass class Group: def get_name(self): pass user = User() group = User() saved1 = user.get_name saved2 = group.get_name flexmock(User).should_receive("get_name").and_return("john") flexmock(Group).should_receive("get_name").and_return("john") assert saved1 != user.get_name assert saved2 != group.get_name assert user.get_name() == "john" assert group.get_name() == "john" flexmock_teardown() assert user.get_name == saved1 assert group.get_name == saved2 def test_flexmock_stubs_are_callable(self): stub = flexmock() mocked = flexmock() mocked.should_receive("create").twice() stub.tickets = mocked # stub.tickets should work with and without parentheses stub.tickets().create() stub.tickets.create() flexmock_teardown() def test_flexmock_respects_at_least_when_called_less_than_requested(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("bar").at_least().twice() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_LEAST mock.method_foo() with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called at least 2 times, called 1 time", ): flexmock_teardown() def test_flexmock_respects_at_least_when_called_requested_number(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").at_least().once() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_LEAST mock.method_foo() flexmock_teardown() def test_flexmock_respects_at_least_when_called_more_than_requested(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").at_least().once() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_LEAST mock.method_foo() mock.method_foo() flexmock_teardown() def test_flexmock_respects_at_most_when_called_less_than_requested(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("bar").at_most().twice() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_MOST mock.method_foo() flexmock_teardown() def test_flexmock_respects_at_most_when_called_requested_number(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").at_most().once() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_MOST mock.method_foo() flexmock_teardown() def test_flexmock_respects_at_most_when_called_more_than_requested(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").at_most().once() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._modifier == AT_MOST mock.method_foo() with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called at most 1 time, called 2 times", ): mock.method_foo() def test_flexmock_treats_once_as_times_one(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").once() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._expected_calls[EXACTLY] == 1 with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() def test_flexmock_treats_twice_as_times_two(self): mock = flexmock(name="temp") mock.should_receive("method_foo").twice().and_return("value_bar") expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._expected_calls[EXACTLY] == 2 with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called exactly 2 times, called 0 times", ): flexmock_teardown() def test_flexmock_works_with_never_when_true(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").never() expectation = FlexmockContainer.get_flexmock_expectation(mock, "method_foo") assert expectation._expected_calls[EXACTLY] == 0 flexmock_teardown() def test_flexmock_works_with_never_when_false(self): mock = flexmock(name="temp") mock.should_receive("method_foo").and_return("value_bar").never() with assert_raises( exceptions.MethodCallError, "method_foo() expected to be called exactly 0 times, called 1 time", ): mock.method_foo() def test_flexmock_get_flexmock_expectation_should_work_with_args(self): mock = flexmock(name="temp") mock.should_receive("method_foo").with_args("value_bar") assert FlexmockContainer.get_flexmock_expectation(mock, "method_foo", "value_bar") def test_mock_kwargs_only_func_mock_all(self): flexmock(some_module).should_receive("kwargs_only_func1").with_args( 1, bar=2, baz=3 ).and_return(123) assert some_module.kwargs_only_func1(1, bar=2, baz=3) == 123 def test_mock_kwargs_only_func_mock_required(self): flexmock(some_module).should_receive("kwargs_only_func1").with_args(1, bar=2).and_return( 123 ) assert some_module.kwargs_only_func1(1, bar=2) == 123 def test_mock_kwargs_only_func_fails_if_required_not_provided(self): with assert_raises( exceptions.MethodSignatureError, 'kwargs_only_func1 requires keyword-only argument "bar"', ): flexmock(some_module).should_receive("kwargs_only_func1").with_args(1) with assert_raises( exceptions.MethodSignatureError, 'kwargs_only_func2 requires keyword-only arguments "bar", "baz"', ): flexmock(some_module).should_receive("kwargs_only_func2").with_args(2) def test_context_manager_on_instance(self): class CM: def __enter__(self): pass def __exit__(self, *_): pass instance = CM() flexmock(instance).should_call("__enter__").once() flexmock(instance).should_call("__exit__").once() with instance: pass flexmock_teardown() def test_context_manager_on_class(self): class CM: def __enter__(self): pass def __exit__(self, *_): pass instance = CM() flexmock(CM).should_receive("__enter__").once() flexmock(CM).should_receive("__exit__").once() with instance: pass flexmock_teardown() def test_flexmock_should_support_with(self): mocked = flexmock() with mocked as mock: mock.should_receive("bar").and_return("baz") assert mocked.bar() == "baz" def test_builtin_open(self): mock = flexmock(sys.modules["builtins"]) fake_fd = flexmock(read=lambda: "some data") mock.should_receive("open").once().with_args("file_name").and_return(fake_fd) with open("file_name") as file: # pylint: disable=unspecified-encoding data = file.read() assert data == "some data" def test_mock_multiple_properties(self): class Foo: @property def prop1(self): return "prop1" @property def prop2(self): return "prop2" mocked = Foo() flexmock(mocked, prop1="mocked1", prop2="mocked2") assert mocked.prop1 == "mocked1" assert mocked.prop2 == "mocked2" def test_mock_property_with_attribute_on_instance(self): class Foo: @property def method(self): return "bar" foo1 = Foo() foo2 = Foo() foo3 = Foo() flexmock(foo1, method="baz") flexmock(foo2, method="baz2") assert foo1.method == "baz" assert foo2.method == "baz2" assert foo3.method == "bar" flexmock_teardown() assert hasattr(Foo, "_flexmock__method") is False, "Property method not cleaned up" assert foo1.method == "bar" assert foo2.method == "bar" assert foo3.method == "bar" def test_mock_property_with_attribute_on_class(self): class Foo: @property def method(self): return "bar" foo1 = Foo() foo2 = Foo() flexmock(Foo, method="baz") assert foo1.method == "baz" assert foo2.method == "baz" flexmock_teardown() assert hasattr(Foo, "_flexmock__method") is False, "Property method not cleaned up" assert foo1.method == "bar" assert foo2.method == "bar" def test_verifying_methods_when_mocking_module(self): # previously, we had problems with recognizing methods vs functions if the mocked # object was an imported module flexmock(some_module).should_receive("ModuleClass").with_args(1, 2) flexmock(some_module).should_receive("module_function").with_args(1, 2) def test_fake_object_supporting_iteration(self): mocked = flexmock() mocked.should_receive("__iter__").and_yield(1, 2, 3) assert list(mocked) == [1, 2, 3] def test_with_args_for_single_named_arg_with_optional_args(self): class FooClass: def method(self, one, two="optional"): pass flexmock(FooClass).should_receive("method").with_args(one=1) def test_with_args_doesnt_set_max_when_using_varargs(self): class FooClass: def method(self, *args): pass flexmock(FooClass).should_receive("method").with_args(1, 2, 3) def test_with_args_doesnt_set_max_when_using_kwargs(self): class FooClass: def method(self, **kwargs): pass flexmock(FooClass).should_receive("method").with_args(1, 2, 3) def test_with_args_blows_up_on_too_few_args(self): class FooClass: def method1(self, arg1): pass def method2(self, arg1, arg2, arg3=1): pass mock = flexmock(FooClass) expectation1 = mock.should_receive("method1") expectation2 = mock.should_receive("method2") with assert_raises( exceptions.MethodSignatureError, "method1 requires at least 1 argument, expectation provided 0", ): expectation1.with_args() with assert_raises( exceptions.MethodSignatureError, "method2 requires at least 2 arguments, expectation provided 1", ): expectation2.with_args(1) def test_with_args_blows_up_on_too_few_args_with_kwargs(self): class FooClass: def method(self, arg1, arg2, arg3=1): pass expectation = flexmock(FooClass).should_receive("method") with assert_raises( exceptions.MethodSignatureError, "method requires at least 3 arguments, expectation provided 2", ): expectation.with_args(1, arg3=2) def test_with_args_blows_up_on_too_many_args(self): class FooClass: def method(self, arg1, arg2, arg3=1): pass expectation = flexmock(FooClass).should_receive("method") with assert_raises( exceptions.MethodSignatureError, "method requires at most 3 arguments, expectation provided 4", ): expectation.with_args(1, 2, 3, 4) def test_with_args_blows_up_on_kwarg_overlapping_positional(self): class FooClass: def method(self, arg1, arg2, arg3=1, **kwargs): pass expectation = flexmock(FooClass).should_receive("method") with assert_raises( exceptions.MethodSignatureError, "['arg3'] already given as positional argument to method", ): expectation.with_args(1, 2, 3, arg3=2) with assert_raises( exceptions.MethodSignatureError, "['arg3', 'arg2'] already given as positional arguments to method", ): expectation.with_args(1, 2, 3, arg3=2, arg2=3) def test_with_args_blows_up_on_invalid_kwarg(self): class FooClass: def method(self, arg1, arg2, arg3=1): pass with assert_raises( exceptions.MethodSignatureError, "d is not a valid keyword argument to method" ): flexmock(FooClass).should_receive("method").with_args(1, 2, d=2) def test_with_args_ignores_invalid_args_on_flexmock_instances(self): instance = flexmock(bar=lambda x: x) instance.should_receive("bar").with_args("stuff") instance.bar("stuff") def test_with_args_does_not_compensate_for_self_on_static_instance_methods(self): class FooClass: @staticmethod def method(arg): pass instance = FooClass() flexmock(instance).should_receive("method").with_args("stuff") instance.method("stuff") def test_with_args_does_not_compensate_for_self_on_static_class_methods(self): class FooClass: @staticmethod def method(arg): pass flexmock(FooClass).should_receive("method").with_args("stuff") FooClass.method("stuff") def test_with_args_does_compensate_for_cls_on_class_methods(self): class FooClass: @classmethod def method(cls, arg): pass instance = FooClass() flexmock(instance).should_receive("method").with_args("stuff") instance.method("stuff") def test_calling_with_keyword_args_matches_mock_with_positional_args(self): class FooClass: def method(self, arg1, arg2, arg3): pass instance = FooClass() flexmock(instance).should_receive("method").with_args(1, 2, 3).once() instance.method(arg1=1, arg2=2, arg3=3) def test_calling_with_positional_args_matches_mock_with_kwargs(self): class FooClass: def method(self, arg1, arg2, arg3): pass instance = FooClass() flexmock(instance).should_receive("method").with_args(arg1=1, arg2=2, arg3=3).once() instance.method(1, 2, arg3=3) def test_and_return_defaults_to_none_with_no_arguments(self): mocked = flexmock() mocked.should_receive("bar").and_return() assert mocked.bar() is None def test_non_callable_attributes_fail_to_set_expectations(self): class FooClass: attribute = 1 instance = FooClass() expectation = flexmock(instance).should_receive("attribute").and_return(2) with assert_raises(exceptions.FlexmockError, "can't use times() with attribute stubs"): expectation.times(1) with assert_raises(exceptions.FlexmockError, "can't use with_args() with attribute stubs"): expectation.with_args(()) with assert_raises( exceptions.FlexmockError, "can't use replace_with() with attribute/property stubs" ): expectation.replace_with(lambda x: x) with assert_raises(exceptions.FlexmockError, "can't use and_raise() with attribute stubs"): expectation.and_raise(Exception) with assert_raises(exceptions.FlexmockError, "can't use when() with attribute stubs"): expectation.when(lambda x: x) with assert_raises(exceptions.FlexmockError, "can't use and_yield() with attribute stubs"): expectation.and_yield(1) with assert_raises(exceptions.FlexmockError, "can't use ordered() with attribute stubs"): object.__getattribute__(expectation, "ordered")() with assert_raises(exceptions.FlexmockError, "can't use at_least() with attribute stubs"): object.__getattribute__(expectation, "at_least")() with assert_raises(exceptions.FlexmockError, "can't use at_most() with attribute stubs"): object.__getattribute__(expectation, "at_most")() with assert_raises(exceptions.FlexmockError, "can't use one_by_one() with attribute stubs"): object.__getattribute__(expectation, "one_by_one")() def test_should_chain_attributes(self): class Class1: x = 1 class Class2: class1 = Class1() class Class3: class2 = Class2() class3 = Class3() mocked = flexmock(class3) mocked.should_receive("class2.class1.x").and_return(2) assert mocked.class2.class1.x == 2 flexmock_teardown() assert mocked.class2.class1.x == 1 def test_mocking_subclass_of_str(self): class String(str): pass string = String() flexmock(string, endswith="fake") assert string.endswith("stuff") == "fake" flexmock_teardown() assert string.endswith("stuff") is False def test_proper_reset_of_subclass_methods(self): class ClassA: def method(self): return "a" class ClassB(ClassA): def method(self): return "b" flexmock(ClassB).should_receive("method").and_return("1") flexmock_teardown() assert ClassB().method() == "b" def test_flexmock_class_returns_same_object_on_repeated_calls(self): class Foo: pass first = flexmock(Foo) second = flexmock(Foo) assert first is second def test_flexmock_object_returns_same_object_on_repeated_calls(self): class Foo: pass instance = Foo() first = flexmock(instance) second = flexmock(instance) assert first is second def test_mocking_down_the_inheritance_chain_class_to_class(self): class Parent: def method1(self): pass class Child(Parent): def method2(self): pass flexmock(Parent).should_receive("method1").and_return("outer") flexmock(Child).should_receive("method2").and_return("inner") assert Parent().method1() == "outer" assert Child().method2() == "inner" def test_flexmock_should_mock_the_same_method_multiple_times(self): class Foo: def method(self): pass instance = Foo() flexmock(instance).should_receive("method").and_return(1) assert instance.method() == 1 flexmock(instance).should_receive("method").and_return(2) assert instance.method() == 2 flexmock(instance).should_receive("method").and_return(3) assert instance.method() == 3 flexmock(instance).should_receive("method").and_return(4) assert instance.method() == 4 def test_new_instances_should_be_a_method(self): class Foo: pass flexmock(Foo).new_instances("bar") assert Foo() == "bar" flexmock_teardown() assert Foo() != "bar" def test_new_instances_raises_error_when_not_a_class(self): class Foo: pass instance = Foo() flexmock(instance) with assert_raises( exceptions.FlexmockError, "new_instances can only be called on a class mock" ): instance.new_instances("bar") def test_new_instances_works_with_multiple_return_values(self): class Foo: pass flexmock(Foo).new_instances("foo", "bar") assert Foo() == "foo" assert Foo() == "bar" def test_should_receive_should_not_replace_flexmock_methods(self): class Foo: pass instance = Foo() flexmock(instance) for method_name in ["should_receive", "should_call", "new_instances"]: with assert_raises(exceptions.FlexmockError, "unable to replace flexmock methods"): instance.should_receive(method_name) def test_flexmock_should_not_add_methods_if_they_already_exist(self): class Foo: def should_receive(self): return "real" def method(self): pass instance = Foo() mock = flexmock(instance) assert instance.should_receive() == "real" assert "should_call" not in dir(instance) assert "new_instances" not in dir(instance) mock.should_receive("method").and_return("baz") assert instance.method() == "baz" flexmock_teardown() assert instance.should_receive() == "real" def test_flexmock_should_not_add_class_methods_if_they_already_exist(self): class Foo: def should_receive(self): return "real" def method(self): pass instance = Foo() mock = flexmock(Foo) assert instance.should_receive() == "real" assert "should_call" not in dir(Foo) assert "new_instances" not in dir(Foo) mock.should_receive("method").and_return("baz") assert instance.method() == "baz" flexmock_teardown() assert instance.should_receive() == "real" def test_flexmock_should_replace_method(self): class Foo: def method(self, arg): return arg instance = Foo() flexmock(instance).should_receive("method").replace_with(lambda x: x == 5) assert instance.method(5) is True assert instance.method(4) is False def test_flexmock_should_replace_cannot_be_specified_twice(self): class Foo: def method(self, arg): return arg instance = Foo() expectation = flexmock(instance).should_receive("method").replace_with(lambda x: x == 5) with assert_raises(exceptions.FlexmockError, "replace_with cannot be specified twice"): expectation.replace_with(lambda x: x == 3) def test_should_give_reasonable_error_for_builtins(self): with assert_raises( exceptions.MockBuiltinError, ( "Python does not allow you to mock builtin objects or modules. " "Consider wrapping it in a class you can mock instead" ), ): flexmock(object) def test_should_give_reasonable_error_for_instances_of_builtins(self): with assert_raises( exceptions.MockBuiltinError, ( "Python does not allow you to mock instances of builtin objects. " "Consider wrapping it in a class you can mock instead" ), ): flexmock(object()) def test_mock_chained_method_calls_works_with_one_level(self): class Foo: def method2(self): return "foo" class Bar: def method1(self): return Foo() instance = Bar() assert instance.method1().method2() == "foo" flexmock(instance).should_receive("method1.method2").and_return("bar") assert instance.method1().method2() == "bar" def test_mock_chained_method_supports_args_and_mocks(self): class Foo: def method2(self, arg): return arg class Bar: def method1(self): return Foo() instance = Bar() assert instance.method1().method2("foo") == "foo" flexmock(instance).should_receive("method1.method2").with_args("foo").and_return( "bar" ).once() assert instance.method1().method2("foo") == "bar" flexmock_teardown() flexmock(instance).should_receive("method1.method2").with_args("foo").and_return( "bar" ).once() with assert_raises( exceptions.MethodCallError, 'method2("foo") expected to be called exactly 1 time, called 0 times', ): flexmock_teardown() def test_mock_chained_method_calls_works_with_more_than_one_level(self): class Baz: def method3(self): return "foo" class Foo: def method2(self): return Baz() class Bar: def method1(self): return Foo() instance = Bar() assert instance.method1().method2().method3() == "foo" flexmock(instance).should_receive("method1.method2.method3").and_return("bar") assert instance.method1().method2().method3() == "bar" def test_flexmock_should_fail_mocking_nonexistent_methods(self): class User: pass user = User() with assert_raises( exceptions.FlexmockError, re.compile( r"<.+\.\.User object at 0x.+> does not have attribute 'nonexistent'" ), ): flexmock(user).should_receive("nonexistent") def test_new_instances_should_blow_up_on_should_receive(self): class User: pass mock = flexmock(User).new_instances(None).mock() with assert_raises(exceptions.FlexmockError, "User does not have attribute 'foo'"): mock.should_receive("foo") def test_flexmock_should_support_mocking_classes_as_functions(self): flexmock(some_module).should_receive("SomeClass").and_return("yay") assert some_module.SomeClass() == "yay" def test_flexmock_should_properly_restore_class_methods(self): class User: @classmethod def get_stuff(cls): return cls.__name__ assert isinstance(User.__dict__["get_stuff"], classmethod) assert User.get_stuff() == "User" flexmock(User).should_receive("get_stuff").and_return("foo") assert User.get_stuff() == "foo" flexmock_teardown() assert User.get_stuff() == "User" assert isinstance(User.__dict__["get_stuff"], classmethod) def test_flexmock_should_mock_same_class_twice(self): class Foo: pass flexmock(Foo) flexmock(Foo) def test_and_raise_with_invalid_arguments(self): with assert_raises( exceptions.FlexmockError, "can't initialize with the given arguments", ): flexmock().should_receive("foo").and_raise(Exception, 1, bar=2) def test_flexmock_should_mock_iter_on_new_style_instances(self): class Foo: def __iter__(self): yield None old = Foo.__iter__ foo1 = Foo() foo2 = Foo() foo3 = Foo() flexmock(foo1, __iter__=iter([1, 2, 3])) flexmock(foo2, __iter__=iter([3, 4, 5])) assert list(foo1) == [1, 2, 3] assert list(foo2) == [3, 4, 5] assert list(foo3) == [None] assert foo1.__iter__ is not old assert foo2.__iter__ is not old assert foo3.__iter__ is not old flexmock_teardown() assert list(foo1) == [None] assert list(foo2) == [None] assert list(foo3) == [None] assert Foo.__iter__ is old, f"{Foo.__iter__} != {old}" def test_flexmock_should_mock_private_methods_with_leading_underscores(self): class ClassWithPrivateMethods: def __private_instance_method(self): pass @classmethod def __private_class_method(cls): pass def instance_method(self): return self.__private_instance_method() @classmethod def class_method(cls): return cls.__private_class_method() # Instance instance = ClassWithPrivateMethods() flexmock(instance).should_receive("__private_instance_method").and_return("bar") assert instance.instance_method() == "bar" # Class flexmock(ClassWithPrivateMethods).should_receive("__private_class_method").and_return("baz") assert ClassWithPrivateMethods.class_method() == "baz" def test_flexmock_should_mock_generators(self): class Gen: def method(self): pass gen = Gen() flexmock(gen).should_receive("method").and_yield(*range(1, 10)) output = list(gen.method()) assert list(range(1, 10)) == output def test_flexmock_should_mock_private_methods(self): class Foo: def __private_method(self): return "foo" def public_method(self): return self.__private_method() instance = Foo() flexmock(instance).should_receive("__private_method").and_return("bar") assert instance.public_method() == "bar" def test_flexmock_should_mock_special_methods(self): class Foo: def __special_method__(self): return "foo" def public_method(self): return self.__special_method__() instance = Foo() flexmock(instance).should_receive("__special_method__").and_return("bar") assert instance.public_method() == "bar" def test_flexmock_should_mock_double_underscore_method(self): class Foo: def __(self): return "foo" def public_method(self): return self.__() instance = Foo() flexmock(instance).should_receive("__").and_return("bar") assert instance.public_method() == "bar" def test_flexmock_should_mock_private_class_methods(self): class Foo: def __iter__(self): pass flexmock(Foo).should_receive("__iter__").and_yield(1, 2, 3) assert list(Foo()) == [1, 2, 3] def test_flexmock_doesnt_error_on_properly_ordered_expectations(self): class Foo: def method1(self): pass def method2(self, arg1): pass def method3(self): pass def method4(self): pass instance = Foo() flexmock(instance).should_receive("method1") flexmock(instance).should_receive("method2").with_args("a").ordered() flexmock(instance).should_receive("method3") flexmock(instance).should_receive("method2").with_args("b").ordered() flexmock(instance).should_receive("method4") instance.method3() instance.method2("a") instance.method2("b") instance.method4() instance.method1() def test_flexmock_errors_on_improperly_ordered_expectations(self): class Foo: def method1(self, arg1): pass instance = Foo() flexmock(instance) instance.should_receive("method1").with_args("a").ordered() instance.should_receive("method1").with_args("b").ordered() with assert_raises( exceptions.CallOrderError, 'method1("b") called before method1(arg1="a")' ): instance.method1("b") def test_flexmock_should_accept_multiple_return_values(self): class Foo: def method1(self): pass instance = Foo() flexmock(instance).should_receive("method1").and_return(1, 5).and_return(2) assert instance.method1() == (1, 5) assert instance.method1() == 2 assert instance.method1() == (1, 5) assert instance.method1() == 2 def test_flexmock_should_accept_multiple_return_values_with_shortcut(self): class Foo: def method1(self): pass instance = Foo() flexmock(instance).should_receive("method1").and_return(1, 2).one_by_one() assert instance.method1() == 1 assert instance.method1() == 2 assert instance.method1() == 1 assert instance.method1() == 2 def test_flexmock_should_accept_multiple_return_values_with_one_by_one(self): mocked = flexmock() flexmock(mocked).should_receive("method1").and_return(2).and_return(3).one_by_one() assert mocked.method1() == 2 assert mocked.method1() == 3 assert mocked.method1() == 2 assert mocked.method1() == 3 def test_one_by_one_called_before_and_return_multiple_values(self): mocked = flexmock() mocked.should_receive("method1").one_by_one().and_return(3, 4) assert mocked.method1() == 3 assert mocked.method1() == 4 assert mocked.method1() == 3 assert mocked.method1() == 4 def test_one_by_one_called_before_and_return_one_value(self): mocked = flexmock() mocked.should_receive("method1").one_by_one().and_return(4).and_return(5) assert mocked.method1() == 4 assert mocked.method1() == 5 assert mocked.method1() == 4 assert mocked.method1() == 5 def test_flexmock_should_mix_multiple_return_values_with_exceptions(self): class Foo: def method1(self): pass instance = Foo() flexmock(instance).should_receive("method1").and_return(1).and_raise(Exception) assert instance.method1() == 1 with assert_raises(Exception, ""): instance.method1() assert instance.method1() == 1 with assert_raises(Exception, ""): instance.method1() def test_flexmock_should_mock_new_instances_with_multiple_params(self): class User: pass class Group: def __init__(self, arg, arg2): pass user = User() flexmock(Group).new_instances(user) assert user is Group(1, 2) def test_flexmock_function_should_return_previously_mocked_object(self): class User: pass user = User() instance = flexmock(user) assert instance == user assert instance == flexmock(user) def test_flexmock_should_not_return_class_object_if_mocking_instance(self): class User: def method(self): pass user = User() user2 = User() class_mock = flexmock(User).should_receive("method").and_return("class").mock() user_mock = flexmock(user).should_receive("method").and_return("instance").mock() assert class_mock is not user_mock assert user.method() == "instance" assert user2.method() == "class" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/ordered.py0000644000000000000000000000346100000000000015255 0ustar00"""Tests for flexmock ordered feature.""" # pylint: disable=missing-docstring,no-self-use,no-member import re from flexmock import exceptions, flexmock from tests.utils import assert_raises class OrderedTestCase: def test_ordered_on_different_methods(self): class String(str): pass string = String("abc") flexmock(string) string.should_call("startswith").with_args("asdf", 0, 4).ordered() string.should_call("endswith").ordered() with assert_raises( exceptions.CallOrderError, re.compile( r'endswith\("c"\) called before startswith' # Argument names are displayed in PyPy r'\((prefix=)?"asdf", (start=)?0, (end=)?4\)' ), ): string.endswith("c") def test_flexmock_ordered_worked_after_default_stub(self): mocked = flexmock() mocked.should_receive("bar") mocked.should_receive("bar").with_args("a").ordered() mocked.should_receive("bar").with_args("b").ordered() with assert_raises(exceptions.CallOrderError, 'bar("b") called before bar("a")'): mocked.bar("b") def test_flexmock_ordered_works_with_same_args(self): mocked = flexmock() mocked.should_receive("bar").ordered().and_return(1) mocked.should_receive("bar").ordered().and_return(2) assert mocked.bar() == 1 assert mocked.bar() == 2 def test_flexmock_ordered_works_with_same_args_after_default_stub(self): mocked = flexmock() mocked.should_receive("bar").and_return(9) mocked.should_receive("bar").ordered().and_return(1) mocked.should_receive("bar").ordered().and_return(2) assert mocked.bar() == 1 assert mocked.bar() == 2 assert mocked.bar() == 9 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/proxied.py0000644000000000000000000001650500000000000015306 0ustar00"""Tests for mocking and spying proxied objects.""" # pylint: disable=missing-docstring,no-self-use,no-member from flexmock import flexmock from tests import some_module from tests.proxy import Proxy from tests.some_module import DerivedClass, SomeClass class ProxiedTestCase: def test_mock_proxied_derived_class_with_args(self): # pylint: disable=not-callable,invalid-name DerivedClassProxy = Proxy(DerivedClass) flexmock(DerivedClassProxy).should_receive("class_method_with_args").with_args( "a" ).and_return(2).twice() assert DerivedClassProxy().class_method_with_args("a") == 2 assert DerivedClassProxy.class_method_with_args("a") == 2 flexmock(DerivedClassProxy).should_receive("static_method_with_args").with_args( "b" ).and_return(3).twice() assert DerivedClassProxy().static_method_with_args("b") == 3 assert DerivedClassProxy.static_method_with_args("b") == 3 instance = DerivedClassProxy() flexmock(instance).should_receive("instance_method_with_args").with_args("c").and_return( 4 ).once() assert instance.instance_method_with_args("c") == 4 def test_mock_proxied_module_function(self): # pylint: disable=not-callable some_module_proxy = Proxy(some_module) flexmock(some_module_proxy).should_receive("module_function").and_return(3).once() assert some_module_proxy.module_function() == 3 def test_mock_proxied_derived_class(self): # pylint: disable=not-callable,invalid-name DerivedClassProxy = Proxy(DerivedClass) flexmock(DerivedClassProxy).should_receive("class_method").and_return(2).twice() assert DerivedClassProxy().class_method() == 2 assert DerivedClassProxy.class_method() == 2 flexmock(DerivedClassProxy).should_receive("static_method").and_return(3).twice() assert DerivedClassProxy().static_method() == 3 assert DerivedClassProxy.static_method() == 3 instance = DerivedClassProxy() flexmock(instance).should_receive("instance_method").and_return(4).once() assert instance.instance_method() == 4 def test_mock_proxied_class_with_args(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) flexmock(SomeClassProxy).should_receive("class_method_with_args").with_args("a").and_return( 2 ).twice() assert SomeClassProxy().class_method_with_args("a") == 2 assert SomeClassProxy.class_method_with_args("a") == 2 flexmock(SomeClassProxy).should_receive("static_method_with_args").with_args( "b" ).and_return(3).twice() assert SomeClassProxy().static_method_with_args("b") == 3 assert SomeClassProxy.static_method_with_args("b") == 3 instance = SomeClassProxy() flexmock(instance).should_receive("instance_method_with_args").with_args("c").and_return( 4 ).once() assert instance.instance_method_with_args("c") == 4 def test_mock_proxied_class(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) flexmock(SomeClassProxy).should_receive("class_method").and_return(2).twice() assert SomeClassProxy().class_method() == 2 assert SomeClassProxy.class_method() == 2 flexmock(SomeClassProxy).should_receive("static_method").and_return(3).twice() assert SomeClassProxy().static_method() == 3 assert SomeClassProxy.static_method() == 3 instance = SomeClassProxy() flexmock(instance).should_receive("instance_method").and_return(4).once() assert instance.instance_method() == 4 def test_spy_proxied_derived_class(self): # pylint: disable=not-callable,invalid-name DerivedClassProxy = Proxy(DerivedClass) flexmock(DerivedClassProxy).should_call("class_method").and_return("class_method").twice() assert DerivedClassProxy().class_method() == "class_method" assert DerivedClassProxy.class_method() == "class_method" flexmock(DerivedClassProxy).should_call("static_method").and_return("static_method").twice() assert DerivedClassProxy().static_method() == "static_method" assert DerivedClassProxy.static_method() == "static_method" instance = DerivedClassProxy() flexmock(instance).should_call("instance_method").and_return("instance_method").once() assert instance.instance_method() == "instance_method" def test_spy_proxied_derived_class_with_args(self): # pylint: disable=not-callable,invalid-name DerivedClassProxy = Proxy(DerivedClass) flexmock(DerivedClassProxy).should_call("class_method_with_args").with_args("a").and_return( "a" ).twice() assert DerivedClassProxy().class_method_with_args("a") == "a" assert DerivedClassProxy.class_method_with_args("a") == "a" flexmock(DerivedClassProxy).should_call("static_method_with_args").with_args( "b" ).and_return("b").twice() assert DerivedClassProxy().static_method_with_args("b") == "b" assert DerivedClassProxy.static_method_with_args("b") == "b" instance = DerivedClassProxy() flexmock(instance).should_call("instance_method_with_args").with_args("c").and_return( "c" ).once() assert instance.instance_method_with_args("c") == "c" def test_spy_proxied_module_function(self): # pylint: disable=not-callable some_module_proxy = Proxy(some_module) flexmock(some_module_proxy).should_receive("module_function").and_return(0).once() assert some_module_proxy.module_function(2, 2) == 0 def test_spy_proxied_class(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) flexmock(SomeClassProxy).should_call("class_method").and_return("class_method").twice() assert SomeClassProxy().class_method() == "class_method" assert SomeClassProxy.class_method() == "class_method" flexmock(SomeClassProxy).should_call("static_method").and_return("static_method").twice() assert SomeClassProxy().static_method() == "static_method" assert SomeClassProxy.static_method() == "static_method" instance = SomeClassProxy() flexmock(instance).should_call("instance_method").and_return("instance_method").once() assert instance.instance_method() == "instance_method" def test_spy_proxied_class_with_args(self): # pylint: disable=not-callable,invalid-name SomeClassProxy = Proxy(SomeClass) flexmock(SomeClassProxy).should_call("class_method_with_args").with_args("a").and_return( "a" ).twice() assert SomeClassProxy().class_method_with_args("a") == "a" assert SomeClassProxy.class_method_with_args("a") == "a" flexmock(SomeClassProxy).should_call("static_method_with_args").with_args("b").and_return( "b" ).twice() assert SomeClassProxy().static_method_with_args("b") == "b" assert SomeClassProxy.static_method_with_args("b") == "b" instance = SomeClassProxy() flexmock(instance).should_call("instance_method_with_args").with_args("c").and_return( "c" ).once() assert instance.instance_method_with_args("c") == "c" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/spying.py0000644000000000000000000004201200000000000015135 0ustar00"""Tests for flexmock spying feature.""" # pylint: disable=missing-docstring,no-self-use,no-member import re from flexmock import exceptions, flexmock from flexmock._api import flexmock_teardown from tests.utils import assert_raises class SpyingTestCase: def test_spying_non_existent_mock_object_method_should_fail(self): mock = flexmock() with assert_raises( exceptions.FlexmockError, "Mock object does not have attribute 'method_foo'. " 'Did you mean to call should_receive("method_foo") instead?', ): mock.should_call("method_foo") mock = flexmock(method_foo=lambda: "ok") mock.should_call("method_foo") def test_pass_thru_should_call_original_method_only_once(self): class Nyan: def __init__(self): self.value = 0 def method(self): self.value += 1 obj = Nyan() flexmock(obj) obj.should_call("method") obj.method() assert obj.value == 1 def test_should_call_works_for_same_method_with_different_args(self): class Foo: def method(self, arg): pass instance = Foo() flexmock(instance).should_call("method").with_args("foo").once() flexmock(instance).should_call("method").with_args("bar").once() instance.method("foo") instance.method("bar") flexmock_teardown() def test_should_call_fails_properly_for_same_method_with_different_args(self): class Foo: def method(self, arg): pass instance = Foo() flexmock(instance).should_call("method").with_args("foo").once() flexmock(instance).should_call("method").with_args("bar").once() instance.method("foo") with assert_raises( exceptions.MethodCallError, 'method(arg="bar") expected to be called exactly 1 time, called 0 times', ): flexmock_teardown() def test_should_call_alias_should_create_a_spy(self): class Foo: def get_stuff(self): return "yay" instance = Foo() flexmock(instance).should_call("get_stuff").and_return("yay").once() with assert_raises( exceptions.MethodCallError, "get_stuff() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() def test_spy_should_not_match_falsy_stuff(self): class Foo: def method1(self): return None def method2(self): return False def method3(self): return [] def method4(self): return "" instance = Foo() flexmock(instance).should_call("method1").and_return("bar").once() flexmock(instance).should_call("method2").and_return("bar").once() flexmock(instance).should_call("method3").and_return("bar").once() flexmock(instance).should_call("method4").and_return("bar").once() with assert_raises( exceptions.FlexmockError, ( "Returned values for call method1 did not match expectation:\n" " Expected:\t'bar'\n" " Returned:\tNone" ), ): instance.method1() with assert_raises( exceptions.FlexmockError, ( "Returned values for call method2 did not match expectation:\n" " Expected:\t'bar'\n" " Returned:\tFalse" ), ): instance.method2() with assert_raises( exceptions.FlexmockError, ( "Returned values for call method3 did not match expectation:\n" " Expected:\t'bar'\n" " Returned:\t[]" ), ): instance.method3() with assert_raises( exceptions.FlexmockError, ( "Returned values for call method4 did not match expectation:\n" " Expected:\t'bar'\n" " Returned:\t''" ), ): instance.method4() def test_spy_should_match_return_value_class(self): class User: pass user = User() instance = flexmock( foo=lambda: ("bar", "baz"), bar=lambda: user, baz=lambda: None, bax=lambda: None, ) instance.should_call("foo").and_return(str, str) instance.should_call("bar").and_return(User) instance.should_call("baz").and_return(object) instance.should_call("bax").and_return(None) assert instance.foo() == ("bar", "baz") assert instance.bar() == user assert instance.baz() is None assert instance.bax() is None def test_flexmock_spy_should_not_clobber_original_method(self): class User: def get_stuff(self): return "real", "stuff" user = User() flexmock(user).should_call("get_stuff") flexmock(user).should_call("get_stuff") assert user.get_stuff() == ("real", "stuff") def test_and_raise_with_value_that_is_not_a_class(self): class RaisesException: def get_stuff(self): raise RuntimeError("baz") instance = RaisesException() flexmock(instance).should_call("get_stuff").and_raise(RuntimeError("foo")).once() with assert_raises( exceptions.ExceptionClassError, re.compile( r"Raised exception for call get_stuff did not match expectation:\n" # Python 3.6 contains comma after 'foo' r" Expected:\tRuntimeError\('foo',?\)\n" r" Raised:\t\n\n" r"Did you try to call and_raise with an instance\?\n" r'Instead of and_raise\(Exception\("arg"\)\), try and_raise\(Exception, "arg"\)', ), ): instance.get_stuff() def test_flexmock_should_blow_up_on_wrong_spy_return_values(self): class User: def get_stuff(self): return "real", "stuff" def get_more_stuff(self): return "other", "stuff" user = User() flexmock(user).should_call("get_stuff").and_return("other", "stuff") with assert_raises( exceptions.MethodSignatureError, ( "Returned values for call get_stuff did not match expectation:\n" " Expected:\t('other', 'stuff')\n" " Returned:\t('real', 'stuff')" ), ): user.get_stuff() flexmock(user).should_call("get_more_stuff").and_return() with assert_raises( exceptions.MethodSignatureError, ( "Returned values for call get_more_stuff did not match expectation:\n" " Expected:\tNone\n" " Returned:\t('other', 'stuff')" ), ): user.get_more_stuff() def test_flexmock_should_reraise_exception_in_spy_with_return_values(self): class RaisesException: @classmethod def class_method(cls): raise RuntimeError("foo") @staticmethod def static_method(): raise RuntimeError("bar") def instance_method(self): raise RuntimeError("baz") instance = RaisesException() flexmock(instance).should_call("class_method").and_return("foo").once() flexmock(instance).should_call("static_method").and_return("bar").once() flexmock(instance).should_call("instance_method").and_return("baz").once() with assert_raises(RuntimeError, "foo"): instance.class_method() with assert_raises(RuntimeError, "bar"): instance.static_method() with assert_raises(RuntimeError, "baz"): instance.instance_method() flexmock(RaisesException).should_call("class_method").once() flexmock(RaisesException).should_call("static_method").once() with assert_raises(RuntimeError, "foo"): RaisesException.class_method() with assert_raises(RuntimeError, "bar"): RaisesException.static_method() def test_flexmock_should_reraise_exception_in_spy(self): class RaisesException: @classmethod def class_method(cls): raise RuntimeError("foo") @staticmethod def static_method(): raise RuntimeError("bar") def instance_method(self): raise RuntimeError("baz") instance = RaisesException() flexmock(instance).should_call("class_method").once() flexmock(instance).should_call("static_method").once() flexmock(instance).should_call("instance_method").once() with assert_raises(RuntimeError, "foo"): instance.class_method() with assert_raises(RuntimeError, "bar"): instance.static_method() with assert_raises(RuntimeError, "baz"): instance.instance_method() flexmock(RaisesException).should_call("class_method").once() flexmock(RaisesException).should_call("static_method").once() with assert_raises(RuntimeError, "foo"): RaisesException.class_method() with assert_raises(RuntimeError, "bar"): RaisesException.static_method() def test_flexmock_should_verify_correct_spy_return_values(self): class User: def get_stuff(self): return "real", "stuff" user = User() flexmock(user).should_call("get_stuff").and_return("real", "stuff") assert user.get_stuff() == ("real", "stuff") def test_flexmock_should_verify_correct_spy_regexp_return_values(self): class User: def get_stuff(self): return "real", "stuff" user = User() flexmock(user).should_call("get_stuff").and_return( re.compile("ea.*"), re.compile("^stuff$") ) assert user.get_stuff() == ("real", "stuff") def test_flexmock_should_verify_spy_raises_correct_exception_class(self): class FakeException(Exception): def __init__(self, param, param2): self.message = f"{param}, {param2}" Exception.__init__(self) class User: def get_stuff(self): raise FakeException(1, 2) user = User() flexmock(user).should_call("get_stuff").and_raise(FakeException, 1, 2) user.get_stuff() def test_flexmock_should_verify_spy_matches_exception_message(self): class FakeException(Exception): def __init__(self, param1, param2): self.param1 = param1 self.param2 = param2 Exception.__init__(self, param1) def __str__(self): return f"{self.param1}, {self.param2}" class User: def get_stuff(self): raise FakeException("1", "2") user = User() flexmock(user).should_call("get_stuff").and_raise(FakeException, "2", "1") with assert_raises( exceptions.ExceptionMessageError, ( "Error message mismatch with raised FakeException:\n" " Expected message:\n\t'1, 2'\n" " Received message:\n\t'2, 1'" ), ): user.get_stuff() def test_flexmock_should_verify_spy_matches_exception_regexp(self): class User: def get_stuff(self): raise Exception("123asdf345") user = User() flexmock(user).should_call("get_stuff").and_raise(Exception, re.compile("asdf")) user.get_stuff() flexmock_teardown() def test_flexmock_should_verify_spy_matches_exception_regexp_mismatch(self): class User: def get_stuff(self): raise Exception("123asdf345") user = User() flexmock(user).should_call("get_stuff").and_raise(Exception, re.compile("^asdf")) with assert_raises( exceptions.ExceptionMessageError, ( "Error message mismatch with raised Exception:\n" " Expected pattern:\n\t/^asdf/\n" " Received message:\n\t'123asdf345'" ), ): user.get_stuff() def test_flexmock_should_blow_up_on_wrong_spy_exception_type(self): class User: def get_stuff(self): raise exceptions.CallOrderError("foo") user = User() flexmock(user).should_call("get_stuff").and_raise(exceptions.MethodCallError) with assert_raises( exceptions.ExceptionClassError, ( "Raised exception for call get_stuff did not match expectation:\n" " Expected:\t\n" " Raised:\t" ), ): user.get_stuff() def test_flexmock_should_match_spy_exception_parent_type(self): class User: def get_stuff(self): raise exceptions.CallOrderError("foo") user = User() flexmock(user).should_call("get_stuff").and_raise(exceptions.FlexmockError) user.get_stuff() def test_flexmock_should_call_respects_matched_expectations(self): class Group: def method1(self, arg1, arg2="b"): return f"{arg1}:{arg2}" def method2(self, arg): return arg group = Group() flexmock(group).should_call("method1").twice() assert group.method1("a", arg2="c") == "a:c" assert group.method1("a") == "a:b" group.should_call("method2").once().with_args("c") assert group.method2("c") == "c" flexmock_teardown() def test_flexmock_should_call_respects_unmatched_expectations(self): class Group: def method1(self, arg1, arg2="b"): return f"{arg1}:{arg2}" def method2(self, arg1): pass group = Group() flexmock(group).should_call("method1").at_least().once() with assert_raises( exceptions.MethodCallError, "method1() expected to be called at least 1 time, called 0 times", ): flexmock_teardown() flexmock(group) group.should_call("method2").with_args("a").once() group.should_receive("method2").with_args("not a") group.method2("not a") with assert_raises( exceptions.MethodCallError, 'method2(arg1="a") expected to be called exactly 1 time, called 0 times', ): flexmock_teardown() def test_flexmock_should_not_blow_up_on_should_call_for_class_methods(self): class User: @classmethod def method(cls): return "class" flexmock(User).should_call("method") assert User.method() == "class" def test_flexmock_should_not_blow_up_on_should_call_for_static_methods(self): class User: @staticmethod def method(): return "static" flexmock(User).should_call("method") assert User.method() == "static" def test_should_call_with_class_default_attributes(self): """Flexmock should not allow mocking class default attributes like __call__ on an instance. """ class WithCall: def __call__(self, arg1): return arg1 instance = WithCall() with assert_raises( exceptions.FlexmockError, re.compile(r".+\.WithCall object at 0x.+> does not have attribute '__call__'"), ): flexmock(instance).should_call("__call__") def test_should_call_on_class_mock(self): class User: def __init__(self): self.value = "value" def method1(self): return "class" def method2(self): return self.value # Access class-level method user1 = User() user2 = User() flexmock(User).should_call("method1").once() with assert_raises( exceptions.MethodCallError, "method1() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() flexmock(User).should_call("method1").twice() assert user1.method1() == "class" assert user2.method1() == "class" # Access instance attributes flexmock(User).should_call("method2").once() with assert_raises( exceptions.MethodCallError, "method2() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() flexmock(User).should_call("method2").twice() assert user1.method2() == "value" assert user2.method2() == "value" # Try resetting the expectation flexmock(User).should_call("method2").once() assert user1.method2() == "value" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/stubbing.py0000644000000000000000000000376500000000000015455 0ustar00"""Tests for flexmock stubbing feature.""" # pylint: disable=missing-docstring,no-self-use,no-member from flexmock import flexmock from flexmock._api import flexmock_teardown from tests import some_module class StubbingTestCase: def test_use_replace_with_for_callable_shortcut_kwargs(self): class Foo: def method(self): return "bar" instance = Foo() flexmock(instance, method=lambda: "baz") assert instance.method() == "baz" def test_should_replace_attributes_that_are_instances_of_classes(self): class Class1: pass class Class2: class1 = Class1() class2 = Class2() flexmock(class2, class1="test") assert class2.class1 == "test" def test_replace_non_callable_instance_attributes(self): class FooClass: def __init__(self): self.attribute = 1 instance1 = FooClass() instance2 = FooClass() flexmock(instance1, attribute=2) flexmock(instance2, attribute=1) assert instance1.attribute == 2 flexmock_teardown() assert instance1.attribute == 1 def test_replace_non_callable_module_attributes(self): flexmock(some_module, MODULE_LEVEL_ATTRIBUTE="yay") assert some_module.MODULE_LEVEL_ATTRIBUTE == "yay" flexmock_teardown() assert some_module.MODULE_LEVEL_ATTRIBUTE == "test" def test_replace_non_callable_class_attributes(self): class FooClass: attribute = 1 instance1 = FooClass() instance2 = FooClass() flexmock(instance1, attribute=2) assert instance1.attribute == 2 assert instance2.attribute == 1 flexmock_teardown() assert instance1.attribute == 1 def test_fake_object_takes_properties(self): fake1 = flexmock(bar=property(lambda self: "baz")) fake2 = flexmock(foo=property(lambda self: "baz")) assert fake1.bar == "baz" assert fake2.foo == "baz" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/features/teardown.py0000644000000000000000000001424200000000000015453 0ustar00"""Tests for flexmock teardown.""" # pylint: disable=missing-docstring,no-self-use,no-member from flexmock import exceptions, flexmock from flexmock._api import UPDATED_ATTRS, flexmock_teardown from tests import some_module from tests.utils import assert_raises class TeardownTestCase: def test_flexmock_should_properly_restore_static_methods(self): class User: @staticmethod def get_stuff(): return "ok!" assert isinstance(User.__dict__["get_stuff"], staticmethod) assert User.get_stuff() == "ok!" flexmock(User).should_receive("get_stuff") assert User.get_stuff() is None flexmock_teardown() assert User.get_stuff() == "ok!" assert isinstance(User.__dict__["get_stuff"], staticmethod) def test_flexmock_should_properly_restore_undecorated_static_methods(self): class User: def get_stuff(): return "ok!" get_stuff = staticmethod(get_stuff) # pylint: disable=no-staticmethod-decorator assert User.get_stuff() == "ok!" flexmock(User).should_receive("get_stuff") assert User.get_stuff() is None flexmock_teardown() assert User.get_stuff() == "ok!" def test_flexmock_should_properly_restore_module_level_functions(self): flexmock(some_module).should_receive("module_function").with_args(1, 2) assert some_module.module_function(1, 2) is None flexmock_teardown() assert some_module.module_function(1, 2) == -1 def test_flexmock_should_revert_new_instances_on_teardown(self): class User: pass class Group: pass user = User() group = Group() flexmock(Group).new_instances(user) assert user is Group() flexmock_teardown() assert group.__class__ is Group().__class__ def test_flexmock_should_cleanup_added_methods_and_attributes(self): class Group: pass group = Group() flexmock(Group) assert "should_receive" in Group.__dict__ assert "should_receive" not in group.__dict__ flexmock(group) assert "should_receive" in group.__dict__ flexmock_teardown() for method in UPDATED_ATTRS: assert method not in Group.__dict__ assert method not in group.__dict__ def test_class_attributes_are_unchanged_after_mocking(self): class Base: @classmethod def class_method(cls): pass @staticmethod def static_method(): pass def instance_method(self): pass class Child(Base): pass instance = Base() base_attrs = list(vars(Base).keys()) instance_attrs = list(vars(instance).keys()) child_attrs = list(vars(Child).keys()) flexmock(Base).should_receive("class_method").once() flexmock(Base).should_receive("static_method").once() Base.class_method() Base.static_method() flexmock(instance).should_receive("class_method").once() flexmock(instance).should_receive("static_method").once() flexmock(instance).should_receive("instance_method").once() instance.class_method() instance.static_method() instance.instance_method() flexmock(Child).should_receive("class_method").once() flexmock(Child).should_receive("static_method").once() Child.class_method() Child.static_method() flexmock_teardown() assert base_attrs == list(vars(Base).keys()) assert instance_attrs == list(vars(instance).keys()) assert child_attrs == list(vars(Child).keys()) def test_class_attributes_are_unchanged_after_spying(self): class Base: @classmethod def class_method(cls): pass @staticmethod def static_method(): pass def instance_method(self): pass class Child(Base): pass instance = Base() base_attrs = list(vars(Base).keys()) instance_attrs = list(vars(instance).keys()) child_attrs = list(vars(Child).keys()) flexmock(Base).should_call("class_method").times(3) # TODO: should be once #80 flexmock(Base).should_call("static_method").times(3) # TODO: should be once #80 Base.class_method() Base.static_method() flexmock(instance).should_call("class_method").once() flexmock(instance).should_call("static_method").once() flexmock(instance).should_call("instance_method").once() instance.class_method() instance.static_method() instance.instance_method() flexmock(Child).should_call("class_method").once() flexmock(Child).should_call("static_method").once() Child.class_method() Child.static_method() flexmock_teardown() assert base_attrs == list(vars(Base).keys()) assert instance_attrs == list(vars(instance).keys()) assert child_attrs == list(vars(Child).keys()) def test_flexmock_should_cleanup_after_exception(self): class User: def method2(self): pass class Group: def method1(self): pass flexmock(Group) flexmock(User) Group.should_receive("method1").once() User.should_receive("method2").once() with assert_raises( exceptions.MethodCallError, "method1() expected to be called exactly 1 time, called 0 times", ): flexmock_teardown() for method in UPDATED_ATTRS: assert method not in dir(Group) for method in UPDATED_ATTRS: assert method not in dir(User) def test_flexmock_teardown_called_between_tests_part1(self): flexmock().should_receive("method1").ordered() def test_flexmock_teardown_called_between_tests_part2(self): mock = flexmock().should_receive("method2").ordered().mock() # Raises CallOrderError if flexmock teardown is not automatically called # after test part 1 above mock.method2() ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1636525627.2754567 flexmock-0.11.3/tests/proxy.py0000644000000000000000000000725300000000000013177 0ustar00"""Proxy class for testing proxied objects.""" class Proxy: """Proxy to another object.""" # OBJECT PROXYING (PYTHON RECIPE) # https://code.activestate.com/recipes/496741-object-proxying/ def __init__(self, obj): object.__setattr__(self, "_obj", obj) def __getattribute__(self, name): return getattr(object.__getattribute__(self, "_obj"), name) def __delattr__(self, name): delattr(object.__getattribute__(self, "_obj"), name) def __setattr__(self, name, value): setattr(object.__getattribute__(self, "_obj"), name, value) def __nonzero__(self): return bool(object.__getattribute__(self, "_obj")) def __str__(self): return str(object.__getattribute__(self, "_obj")) def __repr__(self): return repr(object.__getattribute__(self, "_obj")) _special_names = [ "__abs__", "__add__", "__and__", "__call__", "__cmp__", "__coerce__", "__contains__", "__delitem__", "__delslice__", "__div__", "__divmod__", "__eq__", "__float__", "__floordiv__", "__ge__", "__getitem__", "__getslice__", "__gt__", "__hash__", "__hex__", "__iadd__", "__iand__", "__idiv__", "__idivmod__", "__ifloordiv__", "__ilshift__", "__imod__", "__imul__", "__int__", "__invert__", "__ior__", "__ipow__", "__irshift__", "__isub__", "__iter__", "__itruediv__", "__ixor__", "__le__", "__len__", "__long__", "__lshift__", "__lt__", "__mod__", "__mul__", "__ne__", "__neg__", "__oct__", "__or__", "__pos__", "__pow__", "__radd__", "__rand__", "__rdiv__", "__rdivmod__", "__reduce__", "__reduce_ex__", "__repr__", "__reversed__", "__rfloorfiv__", "__rlshift__", "__rmod__", "__rmul__", "__ror__", "__rpow__", "__rrshift__", "__rshift__", "__rsub__", "__rtruediv__", "__rxor__", "__setitem__", "__setslice__", "__sub__", "__truediv__", "__xor__", "next", ] @classmethod def _create_class_proxy(cls, theclass): """Creates a proxy for the given class.""" def make_method(name): def method(self, *args, **kw): return getattr(object.__getattribute__(self, "_obj"), name)(*args, **kw) return method namespace = {} for name in cls._special_names: if hasattr(theclass, name): namespace[name] = make_method(name) return type(f"{cls.__name__}({theclass.__name__})", (cls,), namespace) def __new__(cls, obj, *args, **kwargs): """Creates an proxy instance referencing `obj`. (obj, *args, **kwargs) are passed to this class' __init__, so deriving classes can define an __init__ method of their own. note: _class_proxy_cache is unique per deriving class (each deriving class must hold its own cache) """ try: cache = cls.__dict__["_class_proxy_cache"] except KeyError: cls._class_proxy_cache = cache = {} try: theclass = cache[obj.__class__] except KeyError: cache[obj.__class__] = theclass = cls._create_class_proxy(obj.__class__) ins = object.__new__(theclass) theclass.__init__(ins, obj, *args, **kwargs) return ins ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/some_module.py0000644000000000000000000000204600000000000014321 0ustar00"""Bogus module for testing.""" # pylint: disable=missing-docstring,disallowed-name,invalid-name,no-self-use MODULE_LEVEL_ATTRIBUTE = "test" class SomeClass: CLASS_VALUE = "class_method" def __init__(self): self.instance_value = "instance_method" @classmethod def class_method(cls): return cls.CLASS_VALUE @classmethod def class_method_with_args(cls, a): return a @staticmethod def static_method(): return "static_method" @staticmethod def static_method_with_args(a): return a def instance_method(self): return self.instance_value def instance_method_with_args(self, a): return a class DerivedClass(SomeClass): pass class ModuleClass: def __init__(self, x, y): self.x = x self.y = y def a(self): return self.x + self.y def module_function(x, y): return x - y def kwargs_only_func1(foo, *, bar, baz=5): return foo + bar + baz def kwargs_only_func2(foo, *, bar, baz): return foo + bar + baz ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641291268.3893943 flexmock-0.11.3/tests/test_doctest.py0000644000000000000000000000417100000000000014516 0ustar00"""Test doctest integration and flexmock API examples.""" # pylint: disable=missing-docstring,no-self-use import doctest import sys from flexmock import _api class Plane: model = "Airpy 1" is_flying = True def __init__(self): self.speed = 3 self.direction = None self.destination = None self.passengers = ["user1", "user2", "user3"] def pilot(self): return self.passengers[0] def fly(self, direction="up", destination="Helsinki"): self.direction = direction self.destination = destination def land(self): return None def set_speed(self, speed): self.speed = speed def repair(self, part): del part def crash(self): return None def flight_log(self): for entry in ["land", "repair"]: yield entry def passenger_count(self): return len(self.passengers) class BadWeatherException(Exception): pass class TestDoctestTeardown: """Test doctest runner teardown.""" def test_flexmock_teardown_works_with_doctest_part_1(self): """Part 1 Examples: Part 1: >>> from flexmock import flexmock >>> flexmock().should_receive("method1").ordered() """ def test_flexmock_teardown_works_with_doctest_part_2(self): """Raises CallOrderError if flexmock teardown is not automatically called after test part 1 above. Examples: Part 2: >>> from flexmock import flexmock >>> mock = flexmock().should_receive("method2").ordered().mock() >>> mock.method2() """ if __name__ == "__main__": results1 = doctest.testmod( sys.modules[__name__], # current module optionflags=doctest.ELLIPSIS, ) results2 = doctest.testmod( _api, extraglobs={ "Plane": Plane, "plane": Plane(), "BadWeatherException": BadWeatherException, }, optionflags=doctest.ELLIPSIS, ) sys.exit(bool(results1.failed + results2.failed)) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/test_generic_integration.py0000644000000000000000000000036600000000000017072 0ustar00"""Test integrations that work with unittest testcases.""" # pylint: disable=missing-docstring,no-self-use import unittest from tests.features import FlexmockTestCase class TestGenericIntegration(FlexmockTestCase, unittest.TestCase): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/test_pytest.py0000644000000000000000000000515600000000000014405 0ustar00"""Test flexmock with pytest.""" # pylint: disable=missing-docstring,redefined-outer-name,no-self-use import unittest import pytest from flexmock import flexmock from flexmock._api import flexmock_teardown from flexmock.exceptions import MethodCallError from tests.features import FlexmockTestCase from tests.utils import assert_raises def test_module_level_test_for_pytest(): flexmock(foo="bar").should_receive("foo").once() with assert_raises( MethodCallError, "foo() expected to be called exactly 1 time, called 0 times" ): flexmock_teardown() @pytest.fixture() def runtest_hook_fixture(): return flexmock(foo="bar").should_receive("foo").once().mock() def test_runtest_hook_with_fixture_for_pytest(runtest_hook_fixture): runtest_hook_fixture.foo() def test_flexmock_teardown_works_with_pytest_part1(): flexmock().should_receive("method1").ordered() def test_flexmock_teardown_works_with_pytest_part2(): mock = flexmock().should_receive("method2").ordered().mock() # Raises CallOrderError if flexmock teardown is not automatically called # after test part 1 above mock.method2() class TestForPytest(FlexmockTestCase): def test_class_level_test_for_pytest(self): flexmock(foo="bar").should_receive("foo").once() with assert_raises( MethodCallError, "foo() expected to be called exactly 1 time, called 0 times" ): flexmock_teardown() class TestUnittestClass(unittest.TestCase): def test_unittest(self): mocked = flexmock(a=2) mocked.should_receive("a").once() with assert_raises( MethodCallError, "a() expected to be called exactly 1 time, called 0 times" ): flexmock_teardown() class TestFailureOnException: def _setup_failing_expectation(self): flexmock(foo="bar").should_receive("foo").once() # Use xfail to ensure we process exceptions as returned by _hook_into_pytest @pytest.mark.xfail(raises=RuntimeError) def test_exception(self): raise RuntimeError("TEST ERROR") @pytest.mark.xfail(raises=MethodCallError) def test_flexmock_raises_if_no_exception(self): self._setup_failing_expectation() @pytest.mark.xfail(raises=RuntimeError) def test_flexmock_doesnt_override_existing_exception(self): self._setup_failing_expectation() raise RuntimeError("Flexmock shouldn't suppress this exception") @pytest.mark.xfail(raises=AssertionError) def test_flexmock_doesnt_override_assertion(self): self._setup_failing_expectation() assert False, "Flexmock shouldn't suppress this assertion" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/test_teamcity.py0000644000000000000000000000067700000000000014677 0ustar00"""Test TeamCity (PyCharm) integration.""" # pylint: disable=missing-docstring,no-self-use import unittest from teamcity.unittestpy import TeamcityTestRunner from tests.features import FlexmockTestCase class TestTeamCityTeardown(FlexmockTestCase, unittest.TestCase): """Test flexmock teardown works with TeamCity test runner (PyCharm).""" if __name__ == "__main__": runner = TeamcityTestRunner() unittest.main(testRunner=runner) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/test_testtools.py0000644000000000000000000000034000000000000015103 0ustar00"""Test testtools integration.""" # pylint: disable=missing-docstring,no-self-use import testtools from tests.features import FlexmockTestCase class TestTestoolsIntegration(FlexmockTestCase, testtools.TestCase): pass ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/test_unittest.py0000644000000000000000000000156200000000000014731 0ustar00"""Test unittest integration.""" # pylint: disable=missing-docstring,no-self-use import sys import unittest from flexmock import flexmock from tests.features import FlexmockTestCase class TestUnitTestIntegration(FlexmockTestCase, unittest.TestCase): """Flexmock unittest integration specific tests.""" def test_failed_test_case(self): """This tests that after a successful tests, failing flexmock assertions will change the test result from successful to failed. """ flexmock().should_receive("this_test_should_fail").once() if __name__ == "__main__": EXPECTED_FAILURES = 1 test = unittest.main(exit=False) if ( len(test.result.failures) == EXPECTED_FAILURES # Make sure that inherited tests are executed and test.result.testsRun > EXPECTED_FAILURES ): sys.exit(0) # OK sys.exit(1) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1641949310.9197485 flexmock-0.11.3/tests/utils.py0000644000000000000000000000271500000000000013154 0ustar00"""Utility functions for testing.""" from contextlib import contextmanager from typing import Type, Union from flexmock._api import RE_TYPE @contextmanager def assert_raises(expected_exception: Type[BaseException], match: Union[RE_TYPE, str, None]): """Assert that code raises the correct exception with a correct error message. Args: expected_exception: Type of the expected exception. match: String or pattern to match the error message against. Use None to skip error message checking. """ try: yield except Exception as raised_exception: if not isinstance(raised_exception, expected_exception): raise AssertionError( f"Expected exception '{type(expected_exception)}' " f"but '{type(raised_exception)}' was raised" ) from raised_exception if match is not None: fail = False if isinstance(match, RE_TYPE): fail = not match.search(str(raised_exception)) match = match.pattern else: fail = str(raised_exception) != str(match) if fail: raise AssertionError( f"Expected error message:\n{'-'*39}\n'{str(match)}'\n" f"\nBut got:\n\n'{str(raised_exception)}'\n{'-'*39}\n" ) from raised_exception else: raise AssertionError(f"Exception '{expected_exception.__name__}' not raised") ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1644455103.222122 flexmock-0.11.3/setup.py0000644000000000000000000001131600000000000012007 0ustar00# -*- coding: utf-8 -*- from setuptools import setup package_dir = \ {'': 'src'} packages = \ ['flexmock'] package_data = \ {'': ['*']} setup_kwargs = { 'name': 'flexmock', 'version': '0.11.3', 'description': 'flexmock is a testing library for Python that makes it easy to create mocks, stubs and fakes.', 'long_description': '

\n banner\n

\n\n

flexmock - Mock, stub, and spy library for Python.

\n\n

\n\n pypi\n\n\n ci\n\n\n documentation\n\n\n codecov\n\n\n license\n\n

\n\n---\n\nFlexmock is a testing library for Python that makes it easy to create mocks, stubs, and fakes.\n\n## Features\n\n- **Mock**: Easily create mock objects and make assertions about which methods or attributes were used and arguments they were called with.\n- **Spy**: Proxy calls to object\'s original methods or attributes and make assertions based on return values or call count.\n- **Fake**: Generate a fake objects to be used in your tests with ease.\n- **Stub**: Create stub objects which replace parts of existing objects and classes with just one call.\n- **No external dependencies**: Flexmock is lightweight and only uses Python standard library. There are no external dependencies.\n- **Simple and intuitive**: Declarations are structured to read more like English sentences than API calls, so they are easy to learn and use.\n- **Fully type annotated**: External API is fully type annotated so it works great with static analysis tools and editor auto-completion.\n- **Integrations with test runners**: Integrates seamlessly with all major test runners like unittest, doctest, and pytest.\n- **Python 3.6+ and PyPy3**: Extensively tested to work with latest Python versions.\n\n## Installation\n\nInstall with pip:\n\n```\npip install flexmock\n```\n\n## Examples\n\nFlexmock features smooth integration with pretty much every popular test runner, so no special setup is necessary. Simply importing flexmock into your test module is sufficient to get started with any of the following examples:\n\n```python\nfrom flexmock import flexmock\n```\n\n### Mocks\n\nAssertions take many flavors and flexmock has many different facilities to generate them:\n\n```python\n# Simplest is ensuring that a certain method is called\nflexmock(Train).should_receive("get_tickets").once()\n\n# Of course, it is also possible to provide a default return value\nflexmock(Train).should_receive("get_destination").and_return("Paris").once()\n\n# Or check that a method is called with specific arguments\nflexmock(Train).should_receive("set_destination").with_args("Seoul").at_least().twice()\n```\n\n### Spies\n\nInstead of mocking, there are also times when you want to execute the actual method and simply find out how many times it was called. Flexmock uses `should_call` to generate this sort of assertions instead of `should_receive`:\n\n```python\n# Verify that a method is called at most three times\nflexmock(Train).should_call("get_tickets").at_most().times(3)\n\n# Make sure that a method is never called with specific arguments\nflexmock(Train).should_call("set_destination").with_args("Helsinki").never()\n\n# More complex example with features like argument type and exception matching\nflexmock(Train).should_call("crash").with_args(str, int).and_raise(AttributeError).once()\n```\n\nSee more examples in the documentation.\n\n## Documentation\n\nUser guide, examples, and a full API reference is available at: https://flexmock.readthedocs.io\n\n## Contributing\n\nContributions are absolutely welcome and encouraged! See [CONTRIBUTING.md](https://github.com/flexmock/flexmock/blob/master/CONTRIBUTING.md) to get started.\n', 'author': 'Slavek Kabrda', 'author_email': None, 'maintainer': 'Adarsh Krishnan', 'maintainer_email': 'adarshk7@gmail.com', 'url': 'https://github.com/flexmock/flexmock', 'package_dir': package_dir, 'packages': packages, 'package_data': package_data, 'python_requires': '>=3.6.2,<4.0.0', } setup(**setup_kwargs) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1644455103.2224336 flexmock-0.11.3/PKG-INFO0000644000000000000000000001275500000000000011402 0ustar00Metadata-Version: 2.1 Name: flexmock Version: 0.11.3 Summary: flexmock is a testing library for Python that makes it easy to create mocks, stubs and fakes. Home-page: https://github.com/flexmock/flexmock License: BSD-2-Clause Keywords: mock,testing,test,unittest,pytest Author: Slavek Kabrda Maintainer: Adarsh Krishnan Maintainer-email: adarshk7@gmail.com Requires-Python: >=3.6.2,<4.0.0 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Testing Classifier: Topic :: Software Development :: Testing :: Mocking Classifier: Topic :: Software Development :: Testing :: Unit Classifier: Typing :: Typed Project-URL: Changes, https://flexmock.readthedocs.io/en/latest/changelog/ Project-URL: Documentation, https://flexmock.readthedocs.io Project-URL: Issue Tracker, https://github.com/flexmock/flexmock/issues Project-URL: Repository, https://github.com/flexmock/flexmock Project-URL: Source Code, https://github.com/flexmock/flexmock Description-Content-Type: text/markdown

banner

flexmock - Mock, stub, and spy library for Python.

pypi ci documentation codecov license

--- Flexmock is a testing library for Python that makes it easy to create mocks, stubs, and fakes. ## Features - **Mock**: Easily create mock objects and make assertions about which methods or attributes were used and arguments they were called with. - **Spy**: Proxy calls to object's original methods or attributes and make assertions based on return values or call count. - **Fake**: Generate a fake objects to be used in your tests with ease. - **Stub**: Create stub objects which replace parts of existing objects and classes with just one call. - **No external dependencies**: Flexmock is lightweight and only uses Python standard library. There are no external dependencies. - **Simple and intuitive**: Declarations are structured to read more like English sentences than API calls, so they are easy to learn and use. - **Fully type annotated**: External API is fully type annotated so it works great with static analysis tools and editor auto-completion. - **Integrations with test runners**: Integrates seamlessly with all major test runners like unittest, doctest, and pytest. - **Python 3.6+ and PyPy3**: Extensively tested to work with latest Python versions. ## Installation Install with pip: ``` pip install flexmock ``` ## Examples Flexmock features smooth integration with pretty much every popular test runner, so no special setup is necessary. Simply importing flexmock into your test module is sufficient to get started with any of the following examples: ```python from flexmock import flexmock ``` ### Mocks Assertions take many flavors and flexmock has many different facilities to generate them: ```python # Simplest is ensuring that a certain method is called flexmock(Train).should_receive("get_tickets").once() # Of course, it is also possible to provide a default return value flexmock(Train).should_receive("get_destination").and_return("Paris").once() # Or check that a method is called with specific arguments flexmock(Train).should_receive("set_destination").with_args("Seoul").at_least().twice() ``` ### Spies Instead of mocking, there are also times when you want to execute the actual method and simply find out how many times it was called. Flexmock uses `should_call` to generate this sort of assertions instead of `should_receive`: ```python # Verify that a method is called at most three times flexmock(Train).should_call("get_tickets").at_most().times(3) # Make sure that a method is never called with specific arguments flexmock(Train).should_call("set_destination").with_args("Helsinki").never() # More complex example with features like argument type and exception matching flexmock(Train).should_call("crash").with_args(str, int).and_raise(AttributeError).once() ``` See more examples in the documentation. ## Documentation User guide, examples, and a full API reference is available at: https://flexmock.readthedocs.io ## Contributing Contributions are absolutely welcome and encouraged! See [CONTRIBUTING.md](https://github.com/flexmock/flexmock/blob/master/CONTRIBUTING.md) to get started.