././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1644454853.1073155
flexmock-0.11.3/CHANGELOG.md 0000644 0000000 0000000 00000007562 00000000000 012116 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1629029293.7464533
flexmock-0.11.3/LICENSE 0000644 0000000 0000000 00000002776 00000000000 011314 0 ustar 00 Copyright 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/README.md 0000644 0000000 0000000 00000007662 00000000000 011565 0 ustar 00
flexmock - Mock, stub, and spy library for Python.
---
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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/docs/advanced/builtin_functions.md 0000644 0000000 0000000 00000001311 00000000000 017044 0 ustar 00 # 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")
)
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/docs/advanced/call_order.md 0000644 0000000 0000000 00000001173 00000000000 015422 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/docs/advanced/chained_methods.md 0000644 0000000 0000000 00000003466 00000000000 016441 0 ustar 00 # 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")
)
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/docs/advanced/generators.md 0000644 0000000 0000000 00000001174 00000000000 015466 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4145355
flexmock-0.11.3/docs/advanced/multiple_return.md 0000644 0000000 0000000 00000001224 00000000000 016543 0 ustar 00 # 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")
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1644454840.8433993
flexmock-0.11.3/docs/advanced/new_instances.md 0000644 0000000 0000000 00000003333 00000000000 016154 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/advanced/replacing_functions.md 0000644 0000000 0000000 00000001311 00000000000 017342 0 ustar 00 # 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().`
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/advanced/state.md 0000644 0000000 0000000 00000002404 00000000000 014432 0 ustar 00 # 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)
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/api.md 0000644 0000000 0000000 00000000124 00000000000 012313 0 ustar 00 # API reference
::: flexmock.flexmock
::: flexmock.Mock
::: flexmock.Expectation
././@PaxHeader 0000000 0000000 0000000 00000000030 00000000000 010206 x ustar 00 24 mtime=1638319852.722
flexmock-0.11.3/docs/changelog.md 0000644 0000000 0000000 00000000176 00000000000 013500 0 ustar 00
{!../CHANGELOG.md!}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1639206773.6128378
flexmock-0.11.3/docs/compare.md 0000644 0000000 0000000 00000011411 00000000000 013171 0 ustar 00 # 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")
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1639206773.6128378
flexmock-0.11.3/docs/conf.py 0000644 0000000 0000000 00000002366 00000000000 012531 0 ustar 00 """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)
]
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1638320433.0064087
flexmock-0.11.3/docs/contributing.md 0000644 0000000 0000000 00000000027 00000000000 014253 0 ustar 00 {!../CONTRIBUTING.md!}
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1639206773.6128378
flexmock-0.11.3/docs/index.md 0000644 0000000 0000000 00000005015 00000000000 012655 0 ustar 00 # Overview
flexmock - Mock, stub, and spy library for Python.
---
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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/start.md 0000644 0000000 0000000 00000011144 00000000000 012703 0 ustar 00 # 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).
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1639206773.6128378
flexmock-0.11.3/docs/toctree.rst 0000644 0000000 0000000 00000000555 00000000000 013427 0 ustar 00 Overview
========
.. 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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/usage/argument_matching.md 0000644 0000000 0000000 00000006116 00000000000 016351 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/usage/call_count.md 0000644 0000000 0000000 00000001640 00000000000 014775 0 ustar 00 # 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()
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4185355
flexmock-0.11.3/docs/usage/intro.md 0000644 0000000 0000000 00000003076 00000000000 014012 0 ustar 00 # 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()
```
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4225354
flexmock-0.11.3/docs/usage/mocking.md 0000644 0000000 0000000 00000010041 00000000000 014274 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525703.4225354
flexmock-0.11.3/docs/usage/spying.md 0000644 0000000 0000000 00000003056 00000000000 014166 0 ustar 00 # 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.
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1644454880.5911262
flexmock-0.11.3/pyproject.toml 0000644 0000000 0000000 00000006424 00000000000 013215 0 ustar 00 [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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1637064346.2723827
flexmock-0.11.3/src/flexmock/__init__.py 0000644 0000000 0000000 00000000343 00000000000 015003 0 ustar 00 """Flexmock testing library for Python."""
from flexmock import _integrations # pylint: disable=unused-import
from flexmock._api import Expectation, Mock, flexmock
__all__ = [
"Expectation",
"Mock",
"flexmock",
]
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1642036081.0123103
flexmock-0.11.3/src/flexmock/_api.py 0000644 0000000 0000000 00000166554 00000000000 014175 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1641292052.891851
flexmock-0.11.3/src/flexmock/_integrations.py 0000644 0000000 0000000 00000015644 00000000000 016123 0 ustar 00 """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)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525627.2714567
flexmock-0.11.3/src/flexmock/exceptions.py 0000644 0000000 0000000 00000001063 00000000000 015425 0 ustar 00 """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"""
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1642036081.0123103
flexmock-0.11.3/src/flexmock/py.typed 0000644 0000000 0000000 00000000000 00000000000 014357 0 ustar 00 ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525627.2714567
flexmock-0.11.3/tests/__init__.py 0000644 0000000 0000000 00000000000 00000000000 013534 0 ustar 00 ././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/__init__.py 0000644 0000000 0000000 00000001633 00000000000 015367 0 ustar 00 """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.
"""
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/arg_matching.py 0000644 0000000 0000000 00000025250 00000000000 016254 0 ustar 00 """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")
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/call_count.py 0000644 0000000 0000000 00000005135 00000000000 015754 0 ustar 00 """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()
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/common.py 0000644 0000000 0000000 00000016020 00000000000 015114 0 ustar 00 """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]
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/conditional.py 0000644 0000000 0000000 00000004046 00000000000 016134 0 ustar 00 """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()
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/derived.py 0000644 0000000 0000000 00000014653 00000000000 015260 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/mocking.py 0000644 0000000 0000000 00000143431 00000000000 015262 0 ustar 00 """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"
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/ordered.py 0000644 0000000 0000000 00000003461 00000000000 015255 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/proxied.py 0000644 0000000 0000000 00000016505 00000000000 015306 0 ustar 00 """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"
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/spying.py 0000644 0000000 0000000 00000042012 00000000000 015135 0 ustar 00 """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"
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/stubbing.py 0000644 0000000 0000000 00000003765 00000000000 015455 0 ustar 00 """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"
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/features/teardown.py 0000644 0000000 0000000 00000014242 00000000000 015453 0 ustar 00 """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()
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1636525627.2754567
flexmock-0.11.3/tests/proxy.py 0000644 0000000 0000000 00000007253 00000000000 013177 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/some_module.py 0000644 0000000 0000000 00000002046 00000000000 014321 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641291268.3893943
flexmock-0.11.3/tests/test_doctest.py 0000644 0000000 0000000 00000004171 00000000000 014516 0 ustar 00 """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))
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/test_generic_integration.py 0000644 0000000 0000000 00000000366 00000000000 017072 0 ustar 00 """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
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/test_pytest.py 0000644 0000000 0000000 00000005156 00000000000 014405 0 ustar 00 """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"
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/test_teamcity.py 0000644 0000000 0000000 00000000677 00000000000 014677 0 ustar 00 """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)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/test_testtools.py 0000644 0000000 0000000 00000000340 00000000000 015103 0 ustar 00 """Test testtools integration."""
# pylint: disable=missing-docstring,no-self-use
import testtools
from tests.features import FlexmockTestCase
class TestTestoolsIntegration(FlexmockTestCase, testtools.TestCase):
pass
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/test_unittest.py 0000644 0000000 0000000 00000001562 00000000000 014731 0 ustar 00 """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)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1641949310.9197485
flexmock-0.11.3/tests/utils.py 0000644 0000000 0000000 00000002715 00000000000 013154 0 ustar 00 """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")
././@PaxHeader 0000000 0000000 0000000 00000000033 00000000000 010211 x ustar 00 27 mtime=1644455103.222122
flexmock-0.11.3/setup.py 0000644 0000000 0000000 00000011316 00000000000 012007 0 ustar 00 # -*- 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
\n
\n\nflexmock - Mock, stub, and spy library for Python.
\n\n\n\n
\n\n\n
\n\n\n
\n\n\n
\n\n\n
\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)
././@PaxHeader 0000000 0000000 0000000 00000000034 00000000000 010212 x ustar 00 28 mtime=1644455103.2224336
flexmock-0.11.3/PKG-INFO 0000644 0000000 0000000 00000012755 00000000000 011402 0 ustar 00 Metadata-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
flexmock - Mock, stub, and spy library for Python.
---
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.