Skip to main content

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

Project description

https://snap-ci.com/butla/mountepy/branch/master/build_image 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 construction 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()

“Real world” use of mountepy can be found in PyDAS.

Measuring test coverage

Mountepy starts your code in a separate process, so it’s normally hard to get information about the code covered by the tests. Fortunately, this problem is solved by Coverage. See this documentation page.

In short, you need to:

  • run coverage.process_startup() in each new Python process (this can be enforced by installing coverage_pth, but some caution is required)

  • set COVERAGE_PROCESS_START environment variable to location of your .coveragerc

  • run the tests themselves: coverage run (...), coverage combine and then coverage report -m

Again, see PyDAS’s tox.ini for demonstration.

Running tests

Clone the repo with submodules, then install and run tox.

$ git clone --recursive git@github.com:butla/mountepy.git
$ sudo pip install tox
$ cd mountepy
$ 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.

Notes

  • Bottle is used to test HTTP services’ handler.

License

Mountepy is licensed under BSD Zero Clause license.

Why I didn’t use one of the more popular licenses like MIT, 2 or 3-Clause BSD or Apache2? Well, this one is practically equal to 2-Clause BSD (and I don’t see any functional differences between it and MIT license) with the exception of the rule about retaining the original license text in derivative work. So if you’d happen to redistribute my library along with your software you don’t have to attach a copy of my license. So you won’t break any copyright laws by being lazy (which I like to be, for instance). You’re welcome.

Project details


Download files

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

Source Distribution

mountepy-0.3.3.tar.gz (9.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mountepy-0.3.3-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file mountepy-0.3.3.tar.gz.

File metadata

  • Download URL: mountepy-0.3.3.tar.gz
  • Upload date:
  • Size: 9.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for mountepy-0.3.3.tar.gz
Algorithm Hash digest
SHA256 7404e362bb9a3320b4303e04f72e48a0686235d16860dddbb1e070a0d67b99b5
MD5 673d9992777280473e9fe71763ff397c
BLAKE2b-256 7c3706b6b84fc6a911bc8258252c0e2adb81fa1bedbf75d8980e2faa210cce84

See more details on using hashes here.

File details

Details for the file mountepy-0.3.3-py3-none-any.whl.

File metadata

File hashes

Hashes for mountepy-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 82726c70504613e28580a3aee1fcc5d79bd6cb82ca03af0b5d657c097031544d
MD5 a75e5d19fa4cc0660bb1d517797ab783
BLAKE2b-256 ec83f9cb5d23f6ea0659177d8c54a488d615a1d19820c55148aedb13d2cc4e50

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page