Debugging flakey tests with pytest-repeat
pytest-repeat is something I reach for whenever I (or someone on my team) encounter a flakey CI test.
The Problem
Just this morning I ran into a flakey test which looked something like:
def request_callback(request):
payload = json.loads(request.body)
num = random.randint(1, 100)
payload["id"] = num
payload["href"] = f"https://api.placeholder.com/posts/{num}"
return (200, {}, json.dumps(payload))
def test_flakey(...):
mocked_responses.add_callback(
responses.POST,
"https://api.placeholder.com/posts",
callback=request_callback,
)
create_post("a") # Makes POST request to /posts, saves to DB
create_post("b")
Can you spot where/why this might fail?
$ pytest test_flakey.py --count=100 -x --pdb -q
...................................F
In my case, I was using the randomly generated ID random.randint(1, 100)
as the primary key for objects in DB, which was causing a UniqueViolation
(psycopg.errors.UniqueViolation) duplicate key value violates unique constraint "post_data_pkey"
Since the test failures were so intermittent pytest-repeat
was super helpful in tracking down & reproducing this specific bug.
The Fix
The fix here was to instead use something deterministic to generate IDs returned from the mocked API.
+import itertools
+
+id_counter = itertools.count()
+
+
def request_callback(request):
- num = random.randint(1, 100)
+ num = next(id_counter)
payload["id"] = num
payload["href"] = f"https://api.placeholder.com/{num}"