11import os
22
33from .mocks import AbeMock
4- from .utils import to_unicode
4+ from .utils import normalize , subkeys
55
66
77class AbeTestMixin (object ):
@@ -33,53 +33,69 @@ def get_sample_request(self, path, label):
3333 sample_request = sample .examples [label ].request
3434 return sample_request .body
3535
36- def assert_data_equal (self , data1 , data2 ):
36+ def assert_item_matches (self , real , sample ):
37+ """
38+ A primitive value matches the sample.
39+
40+ If the sample represents a parameter, then do simple pattern matching.
41+
42+ """
43+ real = normalize (real )
44+ sample = normalize (sample )
45+ self .assertEqual (real , sample )
46+
47+ def assert_data_equal (self , real , sample , ignore = None ):
3748 """
3849 Two elements are recursively equal
50+
51+ :param ignore:
52+ Names of fields to ignore
3953 """
54+ ignore = ignore or []
4055 try :
41- if isinstance (data1 , list ):
42- self .assertIsInstance (data2 , list )
43- self .assert_data_list_equal (data1 , data2 )
44- elif isinstance (data1 , dict ):
45- self .assertIsInstance (data2 , dict )
46- self .assert_data_dict_equal (data1 , data2 )
56+ if isinstance (real , list ):
57+ self .assertIsInstance (sample , list )
58+ self .assert_data_list_equal (real , sample , ignore )
59+ elif isinstance (real , dict ):
60+ self .assertIsInstance (sample , dict )
61+ self .assert_data_dict_equal (real , sample , ignore )
4762 else :
48- data1 = to_unicode (data1 )
49- data2 = to_unicode (data2 )
50- self .assertIsInstance (data2 , data1 .__class__ )
51- self .assertEqual (data1 , data2 )
63+ self .assert_item_matches (real , sample )
5264 except AssertionError as exc :
53- message = str (exc ) + '\n {}\n {}\n \n ' .format (data1 , data2 )
65+ message = str (exc ) + '\n {}\n {}\n \n ' .format (real , sample )
5466 raise type (exc )(message )
5567
56- def assert_data_dict_equal (self , data1 , data2 ):
68+ def assert_data_dict_equal (self , real , sample , ignore = None ):
5769 """
5870 Two dicts are recursively equal without taking order into account
5971 """
72+ ignore = ignore or []
6073 self .assertEqual (
61- len (data1 ), len (data2 ),
74+ len (real ), len (sample ),
6275 msg = 'Number of elements mismatch: {} != {}\n ' .format (
63- data1 .keys (), data2 .keys ())
76+ real .keys (), sample .keys ())
6477 )
65- for key in data1 :
66- self .assertIn (key , data2 )
67- self .assert_data_equal (data1 [key ], data2 [key ])
78+ for key in real :
79+ if key not in ignore :
80+ self .assertIn (key , sample )
81+ inner_ignore = subkeys (ignore , key )
82+ self .assert_data_equal (real [key ], sample [key ], inner_ignore )
6883
69- def assert_data_list_equal (self , data1 , data2 ):
84+ def assert_data_list_equal (self , real , sample , ignore = None ):
7085 """
7186 Two lists are recursively equal, including ordering.
7287 """
88+ ignore = ignore or []
7389 self .assertEqual (
74- len (data1 ), len (data2 ),
90+ len (real ), len (sample ),
7591 msg = 'Number of elements mismatch: {} {}' .format (
76- data1 , data2 )
92+ real , sample )
7793 )
7894
7995 exceptions = []
80- for element , element2 in zip (data1 , data2 ):
96+ for real_item , sample_item in zip (real , sample ):
8197 try :
82- self .assert_data_equal (element , element2 )
98+ self .assert_data_equal (real_item , sample_item , ignore )
8399 except AssertionError as exc :
84100 exceptions .append (exc )
85101
@@ -123,16 +139,19 @@ def assert_matches_request(self, sample_request, wsgi_request):
123139 if 'body' in sample_request :
124140 self .assert_data_equal (wsgi_request .POST , sample_request ['body' ])
125141
126- def assert_matches_response (self , sample_response , wsgi_response ):
142+ def assert_matches_response (self , sample_response , wsgi_response ,
143+ ignore = None ):
127144 """
128145 Check that the sample response and wsgi response match.
129146 """
147+ ignore = ignore or []
130148 self .assertEqual (wsgi_response .status_code , sample_response .status )
131149 if 'body' in sample_response :
132150 response_parsed = wsgi_response .data
133- self .assert_data_equal (response_parsed , sample_response .body )
151+ self .assert_data_equal (
152+ response_parsed , sample_response .body , ignore )
134153
135- def assert_matches_sample (self , path , label , response ):
154+ def assert_matches_sample (self , path , label , response , ignore = None ):
136155 """
137156 Check a URL and response against a sample.
138157
@@ -143,10 +162,15 @@ def assert_matches_sample(self, path, label, response):
143162 :param response:
144163 The actual API response we want to match with the sample.
145164 It is assumed to be a Django Rest Framework response object
165+ :param ignore:
166+ List of fields that will not be checked for strict matching.
167+ You can use this to include server-generated fields whose exact
168+ value you don't care about in your test, like ids, dates, etc.
146169 """
170+ ignore = ignore or []
147171 sample = self .load_sample (path )
148172 sample_request = sample .examples [label ].request
149173 sample_response = sample .examples [label ].response
150174
151- self .assert_matches_response (sample_response , response )
175+ self .assert_matches_response (sample_response , response , ignore = ignore )
152176 self .assert_matches_request (sample_request , response .wsgi_request )
0 commit comments