简体   繁体   中英

Python: testing a method was called inside another method

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'

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM