Usage

The sections below detail different paradigms for using this library. In the documentation below, you’ll learn how to use faux for: 1) mocking a filesystem during testing, 2) defining a test fixture for mocking an external service, 3) mocking dynamic requests with random data, and 4) pulling mock data from an external service for downstream testing.

Filesystem Mocking

For instance, if you have a directory structure that looks like the following:

├── _uuid
├── file
└── query/
    ├── data
    └── arg=test

With the following as contents of the files in that directory structure:

# _uuid
{
    "status": "ok",
    "city": "{{city}}"
}

# file
{
    "status": "ok",
    "month": "{{month}}",
}

# query/arg=test
{
    "status": "ok",
    "arg": "test",
    "digit": {{random_digit}}
}

# query/data
{
    "status": "ok",
    "data": "test"
}

You can serve the directory structure using (the -P option below is specifying a specific port):

~$ faux serve -P 1234 /path/to/directory

And endpoints mirroring that file structure will be available:

>>> import requests
>>> r = requests.get('http://localhost:1234/4db5fd8c-8aa6-4c29-b979-dab3ce71e64e')
>>> print(r.json())
{
    "status": "ok",
    "city": "Sacramento",
}

>>> r = requests.get('http://localhost:1234/file')
>>> print(r.json())
{
    "status": "ok",
    "month": "05"
}

>>> r = requests.get('http://localhost:1234/query?arg=test')
>>> print(r.json())
{
    "status": "ok",
    "arg": "test",
    "digit": 4
}

>>> r = requests.get('http://localhost:1234/query/data')
>>> print(r.json())
{
    "status": "ok",
    "data": "test"
}

It’s also worth noting (alluded to above) that you can mock arbitrary data in your responses using methods from the faker library. Items like {{city}} and {{month}} above were automatically and randomly filled without outputs from a faker.Faker() object during the request. For more information about the types of data you can fake, see the faker documentation.

One other special file above is the _uuid file, which will return data from the _uuid file whenever a uuid is included as part of the request.

Endpoint Mocking

Along with mocking endpoints via filesystem contents, you can also mock endpoints dynamically using the faux library. Here’s and example of how to set up dynamic mocks:

# imports
from faux import Server

# set up app
app = Server(__name__, cache='/path/to/directory')

# define routes for testing
@app.route('/simple', methods=['GET', 'POST', 'PUT', 'DELETE'])
def simple():
    """
    Simple endpint with get/post
    """
    return {
        'status': 'ok',
        'uuid': '{{uuid}}',
        'name': '{{name}}',
        'address': '{{address}}'
    }

@app.route('/nested/<param>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def nested(param):
    """
    Manage server state.
    """
    return {
        'status': 'ok',
        'param': param,
        'company': '{{company}}',
        'number': '{{random_int}}',
    }

# run
if __name__ == '__main__':
    import time
    with app.run(port=1234, debug=True):
        while True:
            time.sleep(1)

Note that faux uses Flask under the hood to manage endpoint resolution and routing, so the API for this library is very similar to the Flask API. The code above will allow you mock all of the contents of a specified directory, and also the dynamic mocks you’ve configured with the route decorator:

>>> import requests
>>> r = requests.get('http://localhost:1234/query/data')
>>> print(r.json())
{
    "status": "ok",
    "data": "test"
}
>>>
>>> r = requests.get('http://localhost:1234/simple')
>>> print(r.json())
{
    "status": "ok",
    "uuid": "4db5fd8c-8aa6-4c29-b979-dab3ce71e64e",
    "name": "Gary Armstrong",
    "address": "97183 Orozco Islands Suite 483\nAndersonton, KS 57080"
}
>>>
>>> r = requests.get('http://localhost:1234/nested/test')
>>> print(r.json())
{
    "status": "ok",
    "param": "test",
    "company": "Perez PLC",
    "number": "8032",
}

Testing Fixtures

One of the most common paradigms for using this software is to mock a service during testing. To do so with this module, you can easily set up a py.test fixture that will run throughout your test session:

import unittest
import pytest

RESOURCES = '/path/to/testing/resources'

@pytest.fixture(scope='session')
def server():
    """
    Set up mock server for testing request caching.
    """
    from faux import Server
    app = Server(__name__, cache=RESOURCES)
    with app.run(port=1234):
        yield
    return

Once you’ve defined the fixture, you can use it on a test class or function like so:

# test function
@pytest.mark.usefixtures("server")
def test_function():
    return


# test class
@pytest.mark.usefixtures("server")
class TestClass(unittest.TestCase):
    def test_method():
        return

With the code above, the server you’re mocking will run throughout your testing session and will gracefully exit when the test session stops.

Caching Request Data

Along with serving a directory structure with request data, you can generate that directory structure by querying data from an existing server. For example, if we already had a service that provided the endpoints we tried to mock above, we could query and save that data in a directory structure (for mocking later on) like so:

>>> from faux import requests
>>> requests.cache('/path/to/cache/directory')
>>> requests.get('http://localhost:1234/file')
>>> requests.get('http://localhost:1234/query?arg=test')
>>> requests.get('http://localhost:1234/query/data')
>>> requests.post('http://localhost:1234/query', json={'data': 'test'})

And the contents of our cache directory will look like:

├── GET/
│   ├── _uuid
│   └── query/
│       ├── data
│       └── arg=test
└── POST/
    └── query/
        └── 91cc355

With the files above containing the data from those requests. After generating that cache directory, you can turn around and serve it for testing using faux serve or using a test fixture.

Command-Line

Along with the serve entrypoint, here is the full set of command-line options available from the faux entry-point:

~$ faux -h
usage: faux [-h] {version,status,serve} ...

positional arguments:
  {version,status,serve}

optional arguments:
  -h, --help            show this help message and exit

Starting a Server

To start a faux server with an existing directory, you can use the serve entrypoint:

~$ faux -h
usage: faux serve [-h] [-P PORT] [-n NAME] [-t TIMEOUT] [-l LOG_LEVEL] path

positional arguments:
  path                  Directory structure to serve.

optional arguments:
  -h, --help            show this help message and exit
  -P PORT, --port PORT  Port to run server on.
  -n NAME, --name NAME  Optional name for server.
  -t TIMEOUT, --timeout TIMEOUT
                        Timeout for stopping server (seconds).
  -l LOG_LEVEL, --log-level LOG_LEVEL
                        Logging verbosity (DEBUG, INFO, ERROR, WARNING,
                        CRITICAL, etc ...). Default is INFO

Example:

~$ faux serve -P 1234 -l INFO -t 100 /path/to/directory

Checking the Status of a Server

To check the status of a running server, you can use the status entrypoint:

~$ faux -h
usage: faux status [-h] [-S] [-H HOST] [-P PORT]

optional arguments:
  -h, --help            show this help message and exit
  -S, --ssl             Use ssl for connecting to server.
  -H HOST, --host HOST  Host to check.
  -P PORT, --port PORT  Port to check.

Example:

~$ faux status -P 1234
{'status': 'ok'}

Questions/Feedback

File an issue in the GitHub issue tracker.