Search code examples
pythonunit-testingpyramid

How should I unit test my Pyramid app's route matching?


I am writing a Pyramid web application that uses URL dispatch for mapping routes to views.

I would like to write a set of unit tests that provide Pyramid's "route matcher" with a variety of paths, and then assert that:

  1. the correct view is called
  2. the request.matchdict contains the expected contents

How can I do this at a proper unit test level (as opposed to at a functional level, by submitting actual HTTP requests)? Which "unit" in Pyramid actually does the route matching, and how can I access it to test my app's configured routing?

NOTE: I know I can do this using functional testing, but I am asking this question because I want to know how to test it much more narrowly--just the route matching portion. I suppose what I'm looking for might be considered an integration test and not a unit test, because it touches multiple components...

I have Googled and read relevant Pyramid documentation, including Dispatching URLs To Views With Routing and Unit, Integration, and Functional Testing. Nothing I have seen shows me how to test my application's configured routes without doing functional tests.


Solution

  • There is not a public api to do this in Pyramid. However, there is a private and pretty stable API for it.. you've been warned.

    Route matching doesn't occur on just patterns but also predicates so it requires a full request object to do matching, not just a url.

    registry = config.registry or request.registry
    mapper = registry.getUtility(pyramid.interfaces.IRoutesMapper)
    result = mapper(request)
    route, matchdict = result['route'], result['match']
    if route is not None:
        route  # pyramid.interfaces.IRoute object
        matchdict  # request.matchdict
    

    The raw IRoute objects themselves are available on a public api via the introspector. You can look these up and match against them on a per-route basis, but this will ignore the route ordering inherent to Pyramid.

    introspector = config.registry or request.registry.introspector
    intr = introspector.get('routes', route_name)
    route = intr['route']
    match = route.match(path)
    if match is not None:
        route  # pyramid.interfaces.IRoute object
        match  # request.matchdict
    

    The route also has the predicates on it which you can pass the request to in order to determine if the predicates pass.