Skip to main content
Join the official 2019 Python Developers SurveyStart the survey!

Utilities for creating (micro)service tests. Based on Mountebank.

Project description

https://travis-ci.org/butla/mountepy.svg?branch=master https://coveralls.io/repos/butla/mountepy/badge.svg?branch=master&service=github https://requires.io/github/butla/mountepy/requirements.svg?branch=master

Utilities for creating (micro)service tests. Based on Mountebank.

Mountepy works by spawning and cleaning after given HTTP service processes and Mountebank. Thanks to that you no longer need that “start X before running the tests” for your application. No. Your tests start “X”, it’s put up or down only when it needs to and as many times as you need.

  • Test-framework-agnostic (use unittest, nose, py.test or whatever… but I like py.test).
  • Enables fast and reliable end-to-end testing of microservices. They won’t be aware that they are in some testing mode.
  • Tested on Python 3.4, Ubuntu 14 x64.
  • Planned features in the road map below. If you have suggestions, just post them as Github issues. Pull requests are also welcome :)

I recommend Pytest for elastic composition of service process test fixtures. Your process may start once per test suite, once per test, etc.

Installation

$ pip install mountepy

A standalone distribution of Mountebank (including NodeJS) will be downloaded on first run.

If you don’t want Mountepy to download Mountebank:

  1. Install NodeJS and NPM. On Ubuntu it’s
$ sudo apt-get install -y nodejs-legacy npm
  1. Install Mountebank yourself
$ npm install -g mountebank --production

Examples

Mountebank acts as a mock for external HTTP services. Here’s how you spawn a Mountebank process, configure it with a stub of some HTTP service, assert that it’s actually responding. Mountebank process is killed after the with block.

# requests is installed alongside Mountepy
import mountepy, requests

with mountepy.Mountebank() as mb:
    imposter = mb.add_imposter_simple(path='/something', response='mock response')
    stub_url = 'http://localhost:{}/something'.format(imposter.port)
    assert requests.get(stub_url).text == 'mock response'

It’s a good idea to test your service as a whole process. Let’s say that you have an one-file WSGI (e.g. Flask or Bottle) app that responds to a GET on its root path ('\') with a string it sees in RET_STR environment variable. Also, the app needs to know on what port to run, so we also pass it as an environment variable. {port} is a special value for Mountepy. It will be filled with the application’s port, whether it’s passed during object costruction or automatically selected from free ports.

# port_for is installed alongside Mountepy
import mountepy, requests, port_for, os, sys

service_port = port_for.select_random()
service = mountepy.HttpService(
    [sys.executable, 'sample_app.py'],
    port=service_port,
    env={
        'PORT': '{port}',
        'RET_STR': 'Just some text.'
    })
with service:
    assert requests.get(service.url).text == 'Just some text.'

Starting a more complex service running on Gunicorn can look like this:

import os, sys

gunicorn_path = os.path.join(os.path.dirname(sys.executable), 'gunicorn')
service_command = [
    gunicorn_path,
    'your_package.app:get_app()',
    '--bind', ':{port}',
    '--enable-stdio-inheritance',
    '--pythonpath', ','.join(sys.path)]

service = HttpService(service_command)

# You can use start/stop methods instead of using the "with" statement.
# It's the same for Mountebank objects.
service.start()

# now you test stuff...
service.stop()

Testing

Install and run tox

$ pip install tox
$ tox

Motivation (on 2015-12-30)

  • Why Mountebank? It can be deployed as standalone application, is actively developed and supports TCP mocks which can be used to simulate broken HTTP messages.
  • Why not Pretenders? Doesn’t support TCP and the development doesn’t seem to be really active.
  • Why not WireMock? Doesn’t support TCP and I don’t want to be forced to install Java to run tests and it doesn’t seem to have more features than Mountebank.
  • Why create a new project? There already is a Python Mountebank wrapper, but it doesn’t offer much.

Road map

  1. Switch license to Creative Commons Zero.
  2. Add example of calling services through client generated with Bravado.
  3. Remove MANIFEST.in like it’s done in PyScaffold.
  4. Check if cycling port_for.is_available() is as good as wait_for_port. If not, add that to port_for.

Notes

  • Bottle is used to test HTTP services’ handler.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for mountepy, version 0.2.1
Filename, size File type Python version Upload date Hashes
Filename, size mountepy-0.2.1.linux-x86_64.tar.gz (13.2 kB) File type Source Python version None Upload date Hashes View hashes
Filename, size mountepy-0.2.1.tar.gz (8.9 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page