How to generate coverage report for http based int

2019-06-23 22:52发布

问题:

I am writing integration tests for a project in which I am making HTTP calls and testing whether they were successful or not.

Since I am not importing any module and not calling functions directly coverage.py report for this is 0%.

I want to know how can I generate coverage report for such integration HTTP request tests?

回答1:

The recipe is pretty much this:

  1. Ensure the backend starts in code coverage mode
  2. Run the tests
  3. Ensure the backend coverage is written to file
  4. Read the coverage from file and append it to test run coverage

Example:

backend

Imagine you have a dummy backend server that responds with a "Hello World" page on GET requests:

# backend.py
from http.server import BaseHTTPRequestHandler, HTTPServer


class DummyHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/html')
        self.end_headers()
        self.wfile.write('<html><body><h1>Hello World</h1></body></html>'.encode())


if __name__ == '__main__':
    HTTPServer(('127.0.0.1', 8000), DummyHandler).serve_forever()

test

A simple test that makes an HTTP request and verifies the response contains "Hello World":

# tests/test_server.py
import requests


def test_GET():
    resp = requests.get('http://127.0.0.1:8000')
    resp.raise_for_status()
    assert 'Hello World' in resp.text

Recipe

# tests/conftest.py
import os
import signal
import subprocess
import time
import coverage.data
import pytest



@pytest.fixture(autouse=True)
def run_backend(cov):
    # 1.
    env = os.environ.copy()
    env['COVERAGE_FILE'] = '.coverage.backend'
    serverproc = subprocess.Popen(['coverage', 'run', 'backend.py'], env=env,
                                  stdout=subprocess.PIPE,
                                  stderr=subprocess.PIPE,
                                  preexec_fn=os.setsid)
    time.sleep(3)
    yield  # 2.
    # 3.
    serverproc.send_signal(signal.SIGINT)
    time.sleep(1)
    # 4.
    backendcov = coverage.data.CoverageData()
    with open('.coverage.backend') as fp:
        backendcov.read_fileobj(fp)
    cov.data.update(backendcov)

cov is the fixture provided by pytest-cov (docs).

Running the test adds the coverage of backend.py to the overall coverage, although only tests selected:

$ pytest --cov=tests --cov-report term -vs
=============================== test session starts ===============================
platform linux -- Python 3.6.5, pytest-3.4.1, py-1.5.3, pluggy-0.6.0 -- 
/data/gentoo64/usr/bin/python3.6
cachedir: .pytest_cache
rootdir: /data/gentoo64/home/u0_a82/projects/stackoverflow/so-50689940, inifile:
plugins: mock-1.6.3, cov-2.5.1
collected 1 item

tests/test_server.py::test_GET PASSED

----------- coverage: platform linux, python 3.6.5-final-0 -----------
Name                   Stmts   Miss  Cover
------------------------------------------
backend.py                12      0   100%
tests/conftest.py         18      0   100%
tests/test_server.py       5      0   100%
------------------------------------------
TOTAL                     35      0   100%


============================ 1 passed in 5.09 seconds =============================