I spent a bit more time on this issue than I'd like to admit, but here's what was going on and what the issue was...
I wanted to test that the following class correctly split up the records, and called the
process
function in proper batches
class EventHandler:
def __init__(self, processor, process_after):
self.processor = processor
self.process_after = process_after
def handle(self, records):
seen = 0
batch = []
for record in records:
if seen == self.process_after:
self.processor.process(batch)
seen = 0
batch.clear()
seen = seen + 1
batch.append(record)
if batch:
self.processor.process(batch)
seen = 0
batch.clear()
I ended up with an initial test that looked like this:
from unittest import mock
from src import handler
def test_handler():
mock_processor = mock.Mock()
h = handler.EventHandler(processor=mock_processor, process_after=2)
h.handle(["1", "2", "3", "4"])
assert mock_processor.process.call_count == 2
That worked just fine, but then, I wanted to assert that the specific calls to
process
contained the correct arguments.
So I added the following assertions:
assert mock_processor.process.call_args_list[0][0] == (["1", "2"],)
assert mock_processor.process.call_args_list[1][0] == (["3", "4"],)
In theory this should have worked just fine, but pytest reported that the calls were actually empty...
def test_handler():
mock_processor = mock.Mock()
h = handler.EventHandler(processor=mock_processor, process_after=2)
h.handle(["1", "2", "3", "4"])
assert mock_processor.process.call_count == 2
> assert mock_processor.process.call_args_list[0][0] == (["1", "2"],)
E AssertionError: assert ([],) == (['1', '2'],)
E At index 0 diff: [] != ['1', '2']
E Use -v to get the full diff
This is where I scratched my head, I even added print statements just before I called
process
and it printed the correct call args.
After a few hours of adding breakpoints and stepping through the code, I realized the issue had to do with mutable lists. Particularly the call to
batch.clear()
I replaced the call to
batch.clear()
with
batch = []
and once I did that pytest reported success.
platform darwin -- Python 3.8.6, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: /Users/beeceej/Code/beeceej/mutable_call_args
collected 1 item
tests/handler_test.py . [100%]
== 1 passed in 0.05s ==
Note to self,
Mock#call_args_list
are mutable, so if your application code mutates params, you won't be able make assertions against them.
...Thanks Python...