Here is my class method:
def create(self, document=None):
resp = self.db.document(None).post(params=document)
if not resp.ok:
logging.exception("Unknown response from Cloudant: %d" % resp.status_code)
raise SystemError("Error creating document")
if resp.ok and document.get("status") == "active":
self.create_eda_document(resp.json().get("id"), document)
return resp
And the test:
def test_create(self):
self.klass.db = mock.MagicMock()
self.klass.db.document = mock.MagicMock()
post_mock = mock.MagicMock()
d = {
'ok': True,
'id': '123',
'rev': '1-bar'
}
resp_mock = mock.MagicMock(ok=True)
resp_mock.__getitem__.side_effect = lambda name: d[name]
post_mock.return_value = resp_mock
post_mock.json.return_value = {"id": "123"}
self.klass.db.document.return_value.post = post_mock
self.klass.create_eda_document = mock.MagicMock(return_value={
'ok': True,
'id': '546',
'rev': '1-baz'
})
resp = self.klass.create(
document={
'workflow': test_workflow(),
'status': 'active',
'name': 'Foo Bar',
'account_id': 100,
'created_at': party_like_its,
'updated_at': party_like_its,
'deleted_at': None
}
)
print(resp)
self.assertDictEqual(
resp,
{
'ok': True,
'id': '123',
'rev': '1-bar'
}
)
self.klass.create_eda_document.assert_called_once_with(
'123',
{
'workflow': test_workflow(),
'status': 'active',
'name': 'Foo Bar',
'account_id': 100,
'created_at': party_like_its,
'updated_at': party_like_its,
'deleted_at': None
}
)
The final self.klass.created_eda_document.assert_called_once_with is failing because it actually isn't being called in the test. It's supposed to run because the document passed into the create method is "active", but the test says it's not. Not sure why it's not running
Update
Here's my test code
def test_create(self):
self.klass.db = mock.MagicMock()
self.klass.db.document = mock.MagicMock()
post_mock = mock.MagicMock(ok=True)
post_mock.return_value = {
'id': '123',
'ok': True,
'rev': '1-bar'
}
self.klass.db.document.return_value.post = post_mock
resp = self.klass.create(
document={
'workflow': test_workflow(),
'status': 'active',
'name': 'Foo Bar',
'account_id': 100,
'created_at': party_like_its,
'updated_at': party_like_its,
'deleted_at': None
}
)
self.assertDictEqual(
resp,
{
'ok': True,
'id': '123',
'rev': '1-bar'
}
)
And here's the error I am receiving:
Traceback (most recent call last):
File "/Users/dmonsewicz/dev/autoresponders/tests/app/utils/test_workflows_cloudant.py", line 126, in test_create
'deleted_at': None
File "/Users/dmonsewicz/dev/autoresponders/app/utils/workflows_cloudant.py", line 40, in create
if not resp.ok:
AttributeError: 'dict' object has no attribute 'ok'
1 Answer 1
First, you need to mock resp.json():
post_mock = mock.MagicMock()
post_mock.json.return_value = {"id": '123'}
self.klass.db.return_value.post = post_mock
Second, you don't actually want to do this:
self.klass.create = mock.MagicMock(return_value={
'ok': True,
'id': '123',
'rev': '1-bar'
})
Since now you've mocked out the create method, which is what is supposed to call create_eda_document.
Also, you need to mock resp differently. It needs to be a dict-like object that also has an ok attribute. I think the best way to do that is to subclass dict:
class fakedict(dict):
def __init__(*args, **kwargs):
super(fakedict, self).__init__(*args, **kwargs)
self.ok = None
...
post_mock = mock.MagicMock()
d = {
'ok': True,
'id': '123',
'rev': '1-bar'
}
resp_mock = fakedict(d)
resp_mock.ok = True
post_mock.return_value = resp_mock
Your test will still pass without this change, though, because resp.ok will end up still being a non-Falsey value.
7 Comments
self.klass.create the response coming back is <MagicMock name='mock.document().post()' id='4463821200'>dict with the self.assertDictEqual call, but it's not really a dict; normal dicts don't have an ok property.resp in this case? You're mocking it anyway. To really test it, you'd need to say self.assertEquals(resp, resp_mock), which seems a bit strange.
create_eda_document.create, don't mock it. Mock its inputs if you need to, but not the method itself.