garnaat / placebo

Make boto3 calls that look real but have no effect.
Apache License 2.0
394 stars 28 forks source link

Spy on method parameters, and still return fake response? #36

Closed ghostsquad closed 8 years ago

ghostsquad commented 8 years ago

I'm wondering if there is anyway to combine placebo functionality with mock. I'd like do something like this:

session = boto3.Session()
pill = placebo.attach(session, data_path=data_path)
pill.playback()
autoscaling = session.client('autoscaling')

# sut setup here
sut.kill_inst_in_asg('foo')
# the system under test (sut) calls:
# autoscaling.terminate_instance_in_auto_scaling_group(InstanceId='foo')

pill.get_method('terminate_instance_in_auto_scaling_group').assert_called_with('foo')
# or
pill.get_method('terminate_instance_in_auto_scaling_group').assert_called_with(InstanceId='foo')
ghostsquad commented 8 years ago

Alternatively, just getting a list containing the method call history, with a parameter dictionary would be cool. That way I can use a different assert library.

jantman commented 8 years ago

I'll agree that I'd like the call parameters to be recorded as well.

I'm not sure if it's possible, but one step past that (in my opinion) would be instead of playing back the responses in order by service and API method, play them back by parameters, so it's no longer order-dependent (or perhaps fall back to explicit order only if there are multiple method calls with the same parameters).

ghostsquad commented 8 years ago

I would definitely like to see different playback options. I'm kinda solving that right now by putting different responses in different folders. But for a more complex application, there would be a lot of duplication in responses.

ghostsquad commented 8 years ago

Ok, I found a way to spy on called methods:

Python 3.5.1 (v3.5.1:37a07cee5969, Dec  5 2015, 21:12:44)
>>> import mock
>>> import boto3
>>> import placebo
>>> session = boto3.Session(aws_access_key_id='a', aws_secret_access_key='b')
>>> pill = placebo.attach(session, data_path='/tmp/aws/responses')
>>> pill.playback()
>>> autoscaling = session.client('autoscaling')
>>> mock_as = mock.Mock(wraps=autoscaling)
>>> result = mock_as.set_desired_capacity(AutoScalingGroupName='foo', DesiredCapacity=0)
>>> print(mock_as.mock_calls)
[call.set_desired_capacity(AutoScalingGroupName='foo', DesiredCapacity=0)]
>>> print(result)
{'ResponseMetadata': {'RequestId': '4e8502e8-d691-11e5-aece-c99d74f60242', 'HTTPStatusCode': 200}}
>>>

so, with dependency injection, I can pass the mock client into the system under test, and get the results I need.

@jantman - I'll close this issue, maybe you could file a new issue for playback features?