# Testing Eventlet

Eventlet is tested using Pytest. To run tests, simply install pytest, and then, in the eventlet tree, do:

    $ pytest

That’s it!

Many tests are skipped based on environmental factors; for example, it makes no sense to test kqueue-specific functionality when your OS does not support it. These are printed as S’s during execution, and in the summary printed after the tests run it will tell you how many were skipped.

## Doctests

To run the doctests included in many of the eventlet modules, use this command:

    $ pytest --doctest-modules eventlet/

The doctests currently do not pass.

## Testing Eventlet Hubs

When you run the tests, Eventlet will use the most appropriate hub for the current platform to do its dispatch. It’s sometimes useful when making changes to Eventlet to test those changes on hubs other than the default. You can do this with the `EVENTLET_HUB` environment variable.

    $ EVENTLET_HUB=epolls pytest

See Understanding Eventlet Hubs for the full list of hubs.

## Writing Tests

What follows are some notes on writing tests, in no particular order.

The filename convention when writing a test for module foo is to name the test foo_test.py. We don’t yet have a convention for tests that are of finer granularity, but a sensible one might be foo_class_test.py.

If you are writing a test that involves a client connecting to a spawned server, it is best to not use a hardcoded port because that makes it harder to parallelize tests. Instead bind the server to 0, and then look up its port when connecting the client, like this:

    server_sock = eventlet.listener(('127.0.0.1', 0))
    client_sock = eventlet.connect(('localhost', server_sock.getsockname()[1]))

## Coverage

Coverage.py is an awesome tool for evaluating how much code was exercised by unit tests. pytest supports it pytest-cov is installed, so it’s easy to generate coverage reports for eventlet. Here’s how:

    pytest --cov=eventlet

After running the tests to completion, this will emit a huge wodge of module names and line numbers. For some reason, the `--cover-inclusive` option breaks everything rather than serving its purpose of limiting the coverage to the local files, so don’t use that.

The html option is quite useful because it generates nicely-formatted HTML files that are much easier to read than line-number soup. Here’s a command that generates the annotation, dumping the html files into a directory called “cover”:

    coverage html -d cover --omit='tempmod,<console>,tests'

(`tempmod` and `console` are omitted because they get thrown away at the completion of their unit tests and coverage.py isn’t smart enough to detect this.)