Skip to content

Commit

Permalink
Support patch.object (#4)
Browse files Browse the repository at this point in the history
* support for patch.object
* improve documentation
* improve changelog
* improve the docstrings
* add integration test
  • Loading branch information
jdkandersson authored Jan 14, 2023
1 parent 4f592f7 commit cdd9c10
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 68 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## [Unreleased]

## [v1.3.0] - 2023-01-14

### Added

- Lint checks that enforce the use of any one or more of the `new`, `spec`,
`spec_set`, `autospec`, or `new_callable` arguments when calling
`unittest.mock.patch.object`.

## [v1.2.0] - 2023-01-14

### Added
Expand Down Expand Up @@ -40,3 +48,4 @@
[v1.0.0]: https://github.com/jdkandersson/flake8-mock-spec/releases/v1.0.0
[v1.1.0]: https://github.com/jdkandersson/flake8-mock-spec/releases/v1.1.0
[v1.2.0]: https://github.com/jdkandersson/flake8-mock-spec/releases/v1.2.0
[v1.3.0]: https://github.com/jdkandersson/flake8-mock-spec/releases/v1.3.0
162 changes: 126 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
# flake8-mock-spec

Do you use mocks and are concerned you are calling methods or accessing
attributes the mocked objects don't have? If not, you should be as that is a
sure way to inject bugs into your code and still have your tests pass. The
`flake8-mock-spec` linter enforces the use of the `spec` argument on mocks
ensuring that your use of mocks is compliant with the interface of the object
being mocked.
Are you using mocks in your code and want to ensure that you are not accessing
or calling methods that the mocked objects don't have? Using mocks incorrectly
can lead to bugs in your code and falsely passing tests. To avoid this,
flake8-mock-spec linter has been created to enforce the use of the spec
argument when creating mocks. This ensures that your use of mocks is compliant
with the interface of the actual object being mocked, and helps you catch
errors early on. Using this linter can save you time and help you write more
robust and maintainable code.

## Getting Started

```shell
python -m venv venv
source ./venv/bin/activate
pip install flake8-mock-spec
flake8 test_source.py
```
To start using `flake8-mock-spec`, you need to install the package and run it
on your source code. Here are the steps to get started:

1. Create a virtual environment and activate it:

```shell
python -m venv venv
source ./venv/bin/activate
```

2. Install `flake8-mock-spec`:

On the following code:
```shell
pip install flake8-mock-spec
```

3. Run `flake8` on your source code:

```shell
flake8 test_source.py
```

For example, consider the following code:

```Python
# test_source.py
Expand All @@ -26,14 +43,15 @@ def test_foo():
mocked_foo = mock.Mock()
```

This will produce warnings such as:
Running `flake8` on this code will produce the following warning:

```shell
flake8 test_source.py
test_source.py:5:22: TMS010 unittest.mock.Mock instances should be constructed with the spec or spec_set argument, more information: https://github.com/jdkandersson/flake8-mock-spec#fix-tms010
```

This can be resolved by changing the code to:
To resolve this warning, you need to specify the `spec` or `spec_set` argument
when creating the mock object:

```Python
# test_source.py
Expand All @@ -47,7 +65,10 @@ def test_foo():

## Rules

A few rules have been defined to allow for selective suppression:
A set of linting rules have been defined to ensure best practices are followed
when using unittest.mock library. These rules allow for selective suppression,
meaning that specific rules can be ignored in certain scenarios. The following
rules have been defined:

* `TMS010`: checks that `unittest.mock.Mock` instances are constructed with the
`spec` or `spec_set` argument.
Expand All @@ -59,10 +80,12 @@ A few rules have been defined to allow for selective suppression:
with the `spec` or `spec_set` argument.
* `TMS020`: checks that `unittest.mock.patch` is called with any one or more of
the `new`, `spec`, `spec_set`, `autospec` or `new_callable` arguments
* `TMS021`: checks that `unittest.mock.patch.object` is called with any one or
more of the `new`, `spec`, `spec_set`, `autospec` or `new_callable` arguments

### Fix TMS010

This linting rule is triggered by creating a `unittest.mock.Mock` instance
This linting rule is triggered when a `unittest.mock.Mock` instance is created
without the `spec` or `spec_set` argument. For example:

```Python
Expand All @@ -72,8 +95,8 @@ def test_foo():
mocked_foo = mock.Mock()
```

This example can be fixed by using the `spec` or `spec_set` argument in the
constructor:
To fix this issue, you need to provide the `spec` or `spec_set` argument when
creating the mock object. Here are a few examples:

```Python
from unittest import mock
Expand All @@ -93,10 +116,14 @@ def test_foo():
mocked_foo = mock.Mock(spec_set=Foo)
```

For more information about `mock.Mock` and how to use it, please refer to the
official documentation:
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock

### Fix TMS011

This linting rule is triggered by creating a `unittest.mock.MagicMock` instance
without the `spec` or `spec_set` argument. For example:
This linting rule is triggered when a `unittest.mock.MagicMock` instance is
created without the `spec` or `spec_set` argument. For example:

```Python
from unittest import mock
Expand All @@ -105,8 +132,8 @@ def test_foo():
mocked_foo = mock.MagicMock()
```

This example can be fixed by using the `spec` or `spec_set` argument in the
constructor:
To fix this issue, you need to provide the `spec` or `spec_set` argument when
creating the mock object. Here are a few examples:

```Python
from unittest import mock
Expand All @@ -126,10 +153,14 @@ def test_foo():
mocked_foo = mock.MagicMock(spec_set=Foo)
```

For more information about `mock.MagicMock` and how to use it, please refer to the
official documentation:
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.MagicMock

### Fix TMS012

This linting rule is triggered by creating a `unittest.mock.NonCallableMock`
instance without the `spec` or `spec_set` argument. For example:
This linting rule is triggered when a `unittest.mock.NonCallableMock` instance
is created without the `spec` or `spec_set` argument. For example:

```Python
from unittest import mock
Expand All @@ -138,8 +169,8 @@ def test_foo():
mocked_foo = mock.NonCallableMock()
```

This example can be fixed by using the `spec` or `spec_set` argument in the
constructor:
To fix this issue, you need to provide the `spec` or `spec_set` argument when
creating the mock object. Here are a few examples:

```Python
from unittest import mock
Expand All @@ -159,10 +190,14 @@ def test_foo():
mocked_foo = mock.NonCallableMock(spec_set=Foo)
```

For more information about `mock.NonCallableMock` and how to use it, please refer to the
official documentation:
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.NonCallableMock

### Fix TMS013

This linting rule is triggered by creating a `unittest.mock.AsyncMock` instance
without the `spec` or `spec_set` argument. For example:
This linting rule is triggered when a `unittest.mock.AsyncMock` instance is
created without the `spec` or `spec_set` argument. For example:

```Python
from unittest import mock
Expand All @@ -171,8 +206,8 @@ def test_foo():
mocked_foo = mock.AsyncMock()
```

This example can be fixed by using the `spec` or `spec_set` argument in the
constructor:
To fix this issue, you need to provide the `spec` or `spec_set` argument when
creating the mock object. Here are a few examples:

```Python
from unittest import mock
Expand All @@ -192,11 +227,17 @@ def test_foo():
mocked_foo = mock.AsyncMock(spec_set=Foo)
```

For more information about `mock.AsyncMock` and how to use it, please refer to the
official documentation:
https://docs.python.org/3/library/unittest.mock.html#unittest.mock.AsyncMock

### Fix TMS020

This linting rule is triggered by calling `unittest.mock.patch` without any one
or more of the `new`, `spec`, `spec_set`, `autospec` or `new_callable`
arguments. For example:
This linting rule is triggered when calling unittest.mock.patch without
including one or more of the following arguments: `new`, `spec`, `spec_set`,
`autospec`, or `new_callable`.

For example, this code will trigger the rule:

```Python
from unittest import mock
Expand All @@ -211,8 +252,8 @@ with mock.patch("Foo") as mocked_foo:
foo_patcher = patch("Foo")
```

This example can be fixed by using any one or more of the `new`, `spec`,
`spec_set`, `autospec` or `new_callable` arguments:
To fix this issue, include one or more of the aforementioned arguments when
calling `mock.patch`. For example:

```Python
from unittest import mock
Expand All @@ -228,3 +269,52 @@ with mock.patch("Foo", spec_set=Foo) as mocked_foo:

foo_patcher = patch("Foo", autospec=True)
```

For more information about `mock.patch` and how to use it, please refer to the
official documentation:
https://docs.python.org/3/library/unittest.mock.html#patch

### Fix TMS021

This linting rule is triggered when calling unittest.mock.patch.object without
including one or more of the following arguments: `new`, `spec`, `spec_set`,
`autospec`, or `new_callable`.

For example, this code will trigger the rule:

```Python
from unittest import mock

from foo import Foo

@mock.patch.object(Foo, "bar")
def test_foo():
pass

with mock.patch.object(Foo, "bar") as mocked_foo:
pass

foo_patcher = patch(Foo, "bar")
```

To fix this issue, include one or more of the aforementioned arguments when
calling `mock.patch.object`. For example:

```Python
from unittest import mock

from foo import Foo

@mock.patch.object(Foo, "bar", spec=Foo.bar)
def test_foo():
pass

with mock.patch.object(Foo, "bar", spec_set=Foo.bar) as mocked_foo:
pass

foo_patcher = patch(Foo, "bar", autospec=True)
```

For more information about `mock.patch.object` and how to use it, please refer
to the official documentation:
https://docs.python.org/3/library/unittest.mock.html#patch
Loading

0 comments on commit cdd9c10

Please sign in to comment.