For tests as simple as this one we would normally collapse the three steps into
a single line. But for more complex tests the test code will be clearer if it’s
separated into three steps, with an empty line between each step:

Arrange: create and setup any objects that you need for the test
(for example, arguments that you need to pass to the function under test).

Act: call the function under test, once only.

Assert: use Python’s assert to test something about the result of
calling the function.

For example, remove_nipsa_action()
is a function that takes an Elasticsearch index name and an annotation and
returns an Elasticsearch action that removes the NIPSA flag from the
annotation. For the purposes of this tutorial it doesn’t really matter what a
“remove nipsa action” is, just know that remove_nipsa_action() takes an
annotation (in the form of a dictionary) as argument and returns an
Elasticsearch action (also a dictionary) in an expected format.

This test still only creates a single object in the arrange step, and only
makes a single assertion in the assert step. Even more complex tests may need
to create multiple objects before calling the function, and then make
multiple assertions at the end.

Almost all Hypothesis tests follow the arrange, act, assert recipe.
This three step recipe is usually a good way to write a test.
The consistency makes the tests easier to understand, and the recipe also
clearly separates setup, what is being tested (the function call), and
verification.

Arrange act assert also discourages the writing of complex tests that try to do
too many things at once. If a test is complicated it can become hard to understand
what the test is for, what it’s supposed to be testing, especially when a future
change to the code causes the test to start failing.

Tip: Try writing the assert part of a test first, and then filling in the
first two steps.

Naming tests

As well as following the arrange act assert recipe, it can really help to make
the intent of your test clear if you give the test function a good name.
The name of a test method should clearly explain the intent of the test.
The names of failing tests are printed out when the test fails, if they’re
named well then the developer can often tell what has gone wrong from the names
of the failing tests alone, without having to look into the test code.
When you do have to look into the code, a good name helps to communicate what
the test is intended to be testing.

Long function names are fine for test functions, since we don’t write code
that calls our test functions (pytest calls them automatically for us) there’s
no benefit to excessive terseness.

test_validate_url() or test_validate_url_1() are poor test names.
test_validate_url_with_a_valid_http_url() is better.
test_validate_url_returns_a_valid_http_url_unmodified() may be even better.