Full ExampleΒΆ
A full example follows.
The RAML:
#%RAML 0.8
# ./example.raml
---
title: example API
mediaType: application/json
protocols: [HTTP]
/users:
get:
description: Get users
post:
description: Create a new user
body:
application/json:
schema: !include schemas/user.json
example: { "username": "marcy" }
/{username}:
get:
description: Get user by username
# ...
# in tests/test_api.py:
import ra
import pytest
api = ra.api('example.raml', app='config:test.ini')
@pytest.fixture(autouse=True)
def clear_database(request, req, app, examples):
# Remember:
# - ``req`` is the pre-bound Ra request for the current test
# - ``request`` is a built-in pytest fixture that holds info about
# the current test context
# - ``app`` is the webtest-wrapped application
# - ``examples`` is a fixture providing the examples factory manager
# for generating data based on RAML ``example`` properties.
import example_app
example_app.clear_db()
example_app.start_transaction()
# login for authentication
app.post('/login', { 'login': 'system', 'password': '123456' })
if req.match(exclude='POST /users'):
# Before any test, except for the one that creates a user,
# we should create the user first.
#
# Passing 'user' to ``examples.build()``
# means to use the example defined for ``POST /users``
marcy = examples.build('user') # returns a dict
example_app.create_user_in_db(marcy)
@request.addfinalizer
def fin():
example_app.rollback_transaction()
app.reset() # clear cookies; logout
# defining a resource scope:
@api.resource('/users')
def users_resource(users):
# scope-local pytest fixtures
#
# a resource scope acts just like a regular module scope
# with respect to pytest fixtures:
@pytest.fixture
def two_hundred():
return 200
# defining tests for methods in this resource:
@users.get
def get(req, two_hundred):
# ``req`` is a callable request object that is pre-bound to the app
# that was passed into ``ra.api`` as well as the URI derived from
# the resource (test scope) and method (test) decorators.
#
# This example uses the other scope-local fixture defined above.
response = req()
assert response.status_code == two_hundred
@users.post
def post_using_example(req):
# By default, when JSON data needs to be sent in the request body,
# Ra will look for an ``example`` property in the RAML definition
# of the resource method's body and use that.
#
# As in WebTest request methods, you can specify the expected
# status code(s), which will be test the response status.
req(status=(201, 409))
# defining a custom user factory; underscored functions are not
# considered tests (but better to import factories from another module)
def _user_factory():
import string
import random
name = ''.join(random.choice(string.ascii_lowercase) for _ in range(10))
email = "{}@example.com".format(name)
return dict(username=name, email=email, password=name)
# using the factory:
@users.post(factory=_user_factory)
def post_using_factory(req):
response = req()
username = req.data['username']
assert username in response
# defining a sub-resource:
@users.resource('/{username}')
def user_resource(user):
# this resource will be requested at /users/{username}
#
# By default, Ra will look at the ``example`` property for
# URI parameters as defined in the RAML, and fill the URI
# template with that.
@user.get
def get(req):
# This is equivalent to the autotest for a resource
# and method:
req()
api.autotest() # autotests will be generated