@@ -231,6 +231,19 @@ It's very important that we test non-happy paths.
231231
232232 Example of how to mock a call with a custom request matching logic
233233==================================================================
234+ ``can_handle_fun `` lets you define matching logic beyond the default
235+ ``path + querystring `` behavior.
236+
237+ The callback receives:
238+
239+ - ``path ``: request path (for example ``/ip ``)
240+ - ``qs_dict ``: parsed query string as returned by ``urllib.parse.parse_qs(..., keep_blank_values=True) ``
241+
242+ .. note ::
243+
244+ When ``can_handle_fun `` is provided, it fully defines matching behavior.
245+ In this case ``match_querystring `` is not used.
246+
234247.. code-block :: python
235248
236249 import json
@@ -239,8 +252,11 @@ Example of how to mock a call with a custom request matching logic
239252 from mocket.mocks.mockhttp import Entry
240253 import requests
241254
255+
242256 @mocketize
243257 def test_can_handle ():
258+ url = " https://httpbin.org"
259+
244260 Entry.single_register(
245261 Entry.GET ,
246262 url,
@@ -255,10 +271,59 @@ Example of how to mock a call with a custom request matching logic
255271 headers = {" content-type" : " application/json" },
256272 can_handle_fun = lambda path , qs_dict : path == " /ip" and not qs_dict,
257273 )
274+
258275 resp = requests.get(" https://httpbin.org/ip" )
259276 assert resp.status_code == 200
260277 assert resp.json() == {" message" : " There you go!" }
261278
279+ Useful patterns
280+ ---------------
281+
282+ Regex path matching:
283+
284+ .. code-block :: python
285+
286+ import re
287+
288+ Entry.single_register(
289+ Entry.GET ,
290+ " https://api.example.com" ,
291+ body = " ok" ,
292+ can_handle_fun = lambda path , qs_dict : bool (re.match(r " ^ /users/\d + $ " , path)),
293+ )
294+
295+ Query parameter checks:
296+
297+ .. code-block :: python
298+
299+ Entry.single_register(
300+ Entry.GET ,
301+ " https://api.example.com" ,
302+ body = " ok" ,
303+ can_handle_fun = lambda path , qs_dict : (
304+ path == " /search"
305+ and qs_dict.get(" q" ) == [" mocket" ]
306+ and qs_dict.get(" limit" , [" 10" ])[0 ].isdigit()
307+ ),
308+ )
309+
310+ Case-insensitive path checks:
311+
312+ .. code-block :: python
313+
314+ Entry.single_register(
315+ Entry.GET ,
316+ " https://api.example.com" ,
317+ body = " ok" ,
318+ can_handle_fun = lambda path , qs_dict : path.lower() == " /healthz" ,
319+ )
320+
321+ Troubleshooting tips
322+ --------------------
323+
324+ - ``parse_qs `` values are lists, so compare against ``["value"] ``.
325+ - Use ``qs_dict.get("key") `` instead of ``qs_dict["key"] `` when parameters are optional.
326+ - Keep callbacks side-effect free; they may run multiple times during request processing.
262327
263328Example of how to record real socket traffic
264329============================================
0 commit comments