2017-10-17 55 views
0

比較我有一個返回該JSON響應的Python:二JSON對象pytest

{ 
    "message": "Staff name and password pair not match", 
    "errors": { 
     "resource": "Login", 
     "field": "staff_authentication", 
     "code": "invalid", 
     "stack_trace": null 
    } 
} 

使用pytest,我想建立的JSON對象的副本,並確保它是完全一樣的

的API
import pytest 
import json 
from collections import namedtuple 
from flask import url_for 
from myapp import create_app 

@pytest.mark.usefixtures('client_class') 
class TestAuth: 

    def test_login(self, client): 
     assert client.get(url_for('stafflogin')).status_code == 405 
     res = self._login(client, 'no_such_user', '123456') 
     assert res.status_code == 422 
     response_object = self._json2obj(res.data) 
     assert response_object.message == 'Staff name and password pair not match' 
     invalid_password_json = dict(message="Staff name and password pair not match", 
            errors=dict(
             resource="Login", 
             code="invalid", 
             field="staff_authentication", 
             stack_trace=None,) 
            ) 
     assert self._ordered(response_object) == self._ordered(invalid_password_json) 

    def _login(self, client, staff_name, staff_password): 
     return client.post('/login', 
      data=json.dumps(dict(staff_name=staff_name, staff_password=staff_password)), 
      content_type='application/json', 
      follow_redirects=True) 

    def _json_object_hook(self, d): return namedtuple('X', d.keys())(*d.values()) 
    def _json2obj(self, data): return json.loads(data, object_hook=self._json_object_hook) 

    def _ordered(self, obj): 
     if isinstance(obj, dict): 
      return sorted((k, self._ordered(v)) for k, v in obj.items()) 
     if isinstance(obj, list): 
      return sorted(self._ordered(x) for x in obj) 
     else: 
      return obj 

pytest顯示2個對象不相等。

>  assert self._ordered(response_object) == self._ordered(invalid_password_json) 
E  AssertionError: assert X(message='St...k_trace=None)) == [('errors', [(...r not match')] 
E   At index 0 diff: 'Staff name and password pair not match' != ('errors', [('code', 'invalid'), ('field', 'staff_authentication'), ('resource', 'Login'), ('stack_trace', None)]) 
E   Full diff: 
E   - X(message='Staff name and password pair not match', errors=X(resource='Login', field='staff_authentication', code='invalid', stack_trace=None)) 
E   + [('errors', 
E   + [('code', 'invalid'), 
E   + ('field', 'staff_authentication'), 
E   + ('resource', 'Login'), 
E   + ('stack_trace', None)]), 
E   + ('message', 'Staff name and password pair not match')] 

tests/test_app.py:31: AssertionError 
=========================== 1 failed in 0.22 seconds =========================== 

如何使新創建的JSON對象與響應相同?

回答

0

如果你確實需要的文字,值到值的兩個doctionaries之間的平等,它會更簡單比較它們的JSON序列化的結果,否則,你將需要類型的字典的一些遞歸的比較和值

:因爲在python類型的字典是無序的集合,你將需要傳遞sort_keys=Truejson.dumps,看this question更多細節

+0

感謝您的回答。 'sort_keys = True'是必要的嗎?即使當我把鑰匙弄混時,比較依然是正確的。 – hanxue

+1

如果你使用python3,這很可能是因爲當前實現的字典是order-preseving,但據我所知它不是有意的,也沒有包含在規範中,所以它可以工作,但我不會長期依靠這一點。在python2中,我認爲這不應該是相同的_一般_,但對於固定鍵列表的短詞 - 它可能沒有sort_keys –

0

相反的轉換JSON響應到對象,我用json.loads()將其轉換我nto a 字典,並進行比較。

def test_login(self, client): 
     res = return client.post('/login', 
      data=json.dumps(dict(staff_name='no_such_user', staff_password='password')), 
      content_type='application/json', 
      follow_redirects=True) 
     assert res.status_code == 422 
     invalid_password_json = dict(message="Staff name and password pair not match", 
            errors=dict(
             resource="Login", 
             code="invalid", 
             field="staff_authentication", 
             stack_trace=None,), 
            ) 
     assert json.loads(res.data) == invalid_password_json 

這樣,我就不必擔心JSON結構的JSON響應空白的差異,以及訂購。只需讓Python的字典比較函數檢查相等性即可。