A Flake8 plugin that checks Python tests follow the Arrange-Act-Assert pattern.
📝 Table of Contents
What is the Arrange-Act-Assert pattern?
"Arrange-Act-Assert" is a testing pattern that focuses each test on a single object's behaviour. It's also known as "AAA" and "3A".
As the name suggests each test is broken down into three distinct parts separated by blank lines:
- Arrange: Set up the object to be tested.
- Act: Carry out an action on the object.
- Assert: Check the expected results have occurred.
For example, a simple test on the behaviour of add
def test(): x = 1 y = 1 result = x + y assert result == 2
As you can see, the Act block starts with
result = and is separated from
the Arrange and Assert blocks by blank lines. The test is focused - it only
contains one add operation and no further additions occur.
Using AAA consistently makes it easier to find the Action in a test. It's therefore always easy to see the object behaviour each test is focused on.
- Arrange-Act-Assert: A Pattern for Writing Good Tests - a great introduction to AAA from a Python perspective.
- Anatomy of a test - a description of Arrange Act Assert in the Pytest documentation.
- Arrange Act Assert pattern for Python developers - information about the pattern and each part of a test.
- Our "good" example files - test examples used in the Flake8-AAA test suite.
What is Flake8?
Flake8 is a command line utility for enforcing style consistency across Python projects. It wraps multiple style checking tools and also runs third-party checks provided by plugins, of which Flake8-AAA is one.
What does Flake8-AAA do?
Flake8-AAA extends Flake8 to check your Python tests match the AAA pattern.
It does this by adding the following checks to Flake8:
- Every test has a single clear Act block.
- Every Act block is distinguished from the code around it with a blank line above and below.
- Arrange and Assert blocks do not contain additional blank lines.
In the future, Flake8-AAA will check that no test has become too complicated and that Arrange blocks do not contain assertions.
Checking your code with these simple formatting rules helps you write simple, consistently formatted tests that match the AAA pattern. They are most helpful if you call Flake8 regularly, for example when you save a file or before you run a test suite.
🏁 Getting Started
Install Flake8 with pip:
pip install flake8
pip install flake8-aaa
You can confirm that Flake8 recognises the plugin by checking its version string:
4.0.1 (aaa: 0.12.0, mccabe: 0.6.1, pycodestyle: 2.8.0, pyflakes: 2.4.0) ...
aaa: 0.12.0 part tells you that Flake8-AAA was installed successfully
and its checks will be used by Flake8.
Let's check the good example from above. We expect Flake8 to return no errors:
curl https://raw.githubusercontent.com/jamescooke/flake8-aaa/master/examples/good/test_example.py > test_example.py flake8 test_example.py
Silence - just what we wanted.
Now let's see a failure from Flake8-AAA. We can use a bad example:
curl https://raw.githubusercontent.com/jamescooke/flake8-aaa/master/examples/bad/test.py > test.py flake8 test.py
test.py:4:1: AAA01 no Act block found in test
Since Flake8-AAA is primarily a Flake8 plugin, the majority of its usage is dependent on how you use Flake8. In general you can point it at your source code and test suite:
flake8 src tests
If you're not already using Flake8 then you might consider:
- Adding a hook to your code editor to run Flake8 when you save a file.
- Adding a pre-commit hook to your source code manager to run Flake8 before you commit.
- Running Flake8 before you execute your test suite - locally or in CI.
If you just want Flake8-AAA error messages you can filter errors returned by
flake8 --select AAA tests
Via command line
Flake8-AAA also provides a command line interface. Although this is primarily for debugging, it can be used to check individual files if you don't want to install Flake8.
python -m flake8_aaa [test_file]
Flake8-AAA works with:
- Pytest and unittest test suites.
- Black and yapf formatted code.
- Mypy and type-annotated code.
- Latest versions of Python 3 (3.6, 3.7, 3.8 and 3.9).
- Full compatibility list - includes information on support for older versions of Python.