Skip to content

Commit

Permalink
Add individual docs pages for AAA02 and AAA04 errors (#234)
Browse files Browse the repository at this point in the history
* WIP add test example for AAA02, plus tweak docs

* Add note about pytest.raises() in Assert blocks, fix missing option ref

* Add examples for AAA02

* Build out AAA02 doc

* Build out AAA04 doc

* Update CHANGELOG

* Fix bad expected output after comment added
  • Loading branch information
jamescooke authored Nov 5, 2023
1 parent aca7194 commit 92db079
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ Changed

* 📕 Version signatures now run on Python 3.12, upgraded from Python 3.11.

* 📕 Build out individual documentation pages for error ``AAA02`` and
``AAA04``. Completes work on `Issue 149
<https://github.com/jamescooke/flake8-aaa/issues/149>`_.

* ⛏️ Make tag recipe fixed to work using grep. `Issue 224
<https://github.com/jamescooke/flake8-aaa/issues/224>`_.

Expand Down
4 changes: 3 additions & 1 deletion docs/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ returned.
If you just want to ignore a particular error, then you can use the more
specific code and indicate the exact error to be ignored. For example, to
ignore the check for a space before the Act block, we can mark the Act block
with ``# noqa: AAA03``::
with ``# noqa: AAA03``:

.. code-block:: python
def test():
x = 1
Expand Down
28 changes: 22 additions & 6 deletions docs/discovery.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ Mark blank lines
Mark all lines in the test that have no characters and are not part of a
string. For example, the following snipped contains only one blank line (line 3
- in the middle of the list), the second at line 9 is part of a string and
therefore not counted::
therefore not counted:

.. code-block:: python
assert result == [
1,
Expand Down Expand Up @@ -92,33 +94,47 @@ Find the Act block
There are four recognised types of Act block:

``marked_act``
Action is marked with Marked with ``# act`` comment::
Action is marked with Marked with ``# act`` comment:

.. code-block:: python
do_thing() # act
``pytest_raises``
Action is wrapped in ``pytest.raises`` context manager::
Action is wrapped in one of Pytest's context managers: ``pytest.raises()``,
``pytest.warns()`` or ``pytest.deprecated_call()``:

.. code-block:: python
with pytest.raises(ValueError):
do_thing()
``result_assignment``
``result =`` action::
``result =`` action:

.. code-block:: python
result = do_thing()
``unittest_raises``
Action is wrapped in unittest's ``assertRaises`` context manager::
Action is wrapped in unittest's ``assertRaises`` context manager:

.. code-block:: python
with self.assertRaises(ValueError):
do_thing()
Flake8-AAA searches each test function for lines that look like Act blocks. It
will raise an error when a function does not have exactly 1 Act block.

However, note assertions that exceptions are raised can also be used in Assert
blocks. When Flake8-AAA finds a suitable ``marked_act`` or
``result_assignment`` node, it will allow ``pytest_raises`` nodes in the Assert
block.

The "act block style" configuration allows for a "large" style of Act block to
be specified, which changes how Act blocks are built in relation to context
managers. See ... # TODO225 fix this ref
managers. See :ref:`Act block style option <option-act-block-style>`.

Build Arrange and Assert blocks
...............................
Expand Down
62 changes: 52 additions & 10 deletions docs/error_codes/AAA02-multiple-act-blocks-found-in-test.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,56 @@
AAA02: multiple Act blocks found in test
----------------------------------------
========================================

There must be one and only one Act block in every test but Flake8-AAA found
more than one potential Act block. This error is usually triggered when a test
contains more than one ``result =`` statement or more than one line marked ``#
act``. Multiple Act blocks create ambiguity and raise this error code.
Flake8-AAA checks that every test has a single, clear Act block.

Resolution
..........
When Flake8-AAA raises ``AAA02`` it found more than one Act block in a
particular test.

Split the failing test into multiple tests. Where there is complicated or
reused set-up code then apply the DRY principle and extract the reused code
into one or more fixtures.
Problematic code
----------------

.. code-block:: python
def test() -> None:
x = 1
y = 2
result = x + y
assert result == 3
result = 2 * x + 2 * y
assert result == 6
Correct code
------------

Split the one test with two Act blocks into two distinct tests.

.. code-block:: python
def test_A() -> None:
x = 1
y = 2
result = x + y
assert result == 3
def test_B() -> None:
x = 1
y = 2
result = 2 * x + 2 * y
assert result == 6
Rationale
---------

Each test carries out a single action and tests its result.

Having multiple actions in a test create ambiguity because it can become less
clear which behaviour is being tested.

Where there is complicated or reused set-up code, then apply the DRY principle
and extract the reused code into one or more fixtures.
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
AAA04: expected 1 blank line before Assert block, found none
------------------------------------------------------------
============================================================

For tests that have an Assert block, there must be a blank line between the Act
and Assert blocks, but Flake8-AAA could not find one.

This blank line creates separation between the action and the assertions and
makes the Act block easy to spot.
Prerequisites
-------------

This rule works best with `pycodestyle
<https://pypi.org/project/pycodestyle/>`_'s ``E303`` rule enabled because it
ensures that there are not multiple blank lines between the blocks.

Problematic code
----------------

As with rule ``AAA03``, this rule works best with ``E303`` enabled.
.. code-block:: python
Resolution
..........
def test() -> None:
x = 3
result = x**5
assert result == 243
Correct code
------------

Add a blank line before the Assert block.

.. code-block:: python
def test() -> None:
x = 3
result = x**5
assert result == 243
Rationale
---------

This blank line creates separation between the action and the assertions - it
makes the Act block easy to spot.
2 changes: 2 additions & 0 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ configuration files.
All names of Flake8-AAA's options and configuration values are prefixed with
"aaa". E.g. ``--aaa-act-block-style``.

.. _option-act-block-style:

Act block style
---------------

Expand Down
2 changes: 2 additions & 0 deletions examples/bad/bad_expected.out
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ examples/bad/test.py:4:1: AAA01 no Act block found in test
examples/bad/test_aaa01.py:8:1: AAA01 no Act block found in test
examples/bad/test_aaa01_cm_import.py:11:1: AAA01 no Act block found in test
examples/bad/test_aaa01_cm_import.py:18:1: AAA01 no Act block found in test
examples/bad/test_aaa02.py:19:1: AAA02 multiple Act blocks found in test
examples/bad/test_aaa02.py:5:1: AAA02 multiple Act blocks found in test
examples/bad/test_aaa03.py:10:9: AAA03 expected 1 blank line before Act block, found none
examples/bad/test_aaa03.py:3:5: AAA03 expected 1 blank line before Act block, found none
examples/bad/test_aaa03_04.py:10:5: AAA04 expected 1 blank line before Assert block, found none
Expand Down
28 changes: 28 additions & 0 deletions examples/bad/test_aaa02.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# NOTE: tests _can_ use pytest.raises() in Assert blocks. See discovery docs
# and examples/good/test_with_statement.py


def test() -> None:
"""
Two result assignment statements will raise AAA02
"""
x = 1
y = 2

result = x + y

assert result == 3
result = 2 * x + 2 * y
assert result == 6


def test_act() -> None:
"""
One result and act hint will raise
"""
x = 1
y = 2

result = x + y

assert result == 3 # act
2 changes: 1 addition & 1 deletion examples/black/noqa/test_02.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def test(): # noqa: AAA02
def test() -> None: # noqa: AAA02
result = 1

assert result == 1
Expand Down
2 changes: 1 addition & 1 deletion examples/good/noqa/test_02.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def test(): # noqa: AAA02
def test() -> None: # noqa: AAA02
result = 1

assert result == 1
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ commands =
examples/good/test_with_statement_unittest.py \
examples/good/test_assignment_operator.py \
examples/bad/file_pattern_test.py \
examples/bad/test_aaa02.py \
examples/bad/test_aaa03.py \
examples/bad/test_aaa03_04.py \
examples/bad/test_aaa04.py \
Expand Down

0 comments on commit 92db079

Please sign in to comment.