如何为基于 http 的集成测试生成覆盖率报告?

Posted

技术标签:

【中文标题】如何为基于 http 的集成测试生成覆盖率报告?【英文标题】:How to generate coverage report for http based integration tests? 【发布时间】:2018-11-14 08:11:42 【问题描述】:

我正在为一个项目编写集成测试,我在该项目中进行 HTTP 调用并测试它们是否成功。

由于我没有导入任何模块,也没有直接调用函数,因此覆盖率.py 报告为 0%。

我想知道如何为此类集成 HTTP 请求测试生成覆盖率报告?

【问题讨论】:

【参考方案1】:

配方差不多是这样的:

    确保后端以代码覆盖模式启动 运行测试 确保将后端覆盖写入文件 从文件中读取覆盖率并将其附加到测试运行覆盖率

例子:

后端

假设您有一个虚拟后端服务器,它在 GET 请求上响应“Hello World”页面:

# 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()

测试

发出 HTTP 请求并验证响应是否包含“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

食谱

# 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)

covpytest-cov(docs)提供的fixture。

运行测试会将backend.py 的覆盖率添加到整体覆盖率中,尽管只选择了tests

$ 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/***/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 =============================

【讨论】:

上述覆盖覆盖方法出现错误。运行 pytest 时,.coverage 被覆盖。我收到此错误coverage.misc.CoverageException: Doesn't seem to be a coverage.py data file 这可能是由于pytest 和后端related issue 中的coverage 包的版本冲突。 随着我认为 coverage 5.4 最近的变化,我认为最后四行应该改为 backendcov = coverage.data.CoverageData(basename='.coverage.backend') backendcov.read() cov.get_data ().update(backendcov)【参考方案2】:

使用 Coverage 5.1,基于 "Measuring sub-processes" section of the coverage.py docs,您可以设置 COVERAGE_PROCESS_START env-var,在代码中的某处调用 coverage.process_startup()。如果您在.coveragerc 中设置parallel=True

    在您的流程中的某处,调用此代码:

    import coverage
    coverage.process_startup()
    

    这可以在全局sitecustomize.py 中完成,但在我的情况下,很容易将其添加到我的应用程序的__init__.py,我在其中添加了:

    import os
    if 'COVERAGE_PROCESS_START' in os.environ:
        import coverage
        coverage.process_startup()
    

    为了安全起见,我在if 语句中添加了一个额外的检查(检查是否还设置了MYAPP_COVERAGE_SUBPROCESS

    在您的测试用例中,将COVERAGE_PROCESS_START 设置为您的.coveragerc 文件的路径(如果不需要此配置,则为空字符串),例如:

    import os
    import subprocess
    
    env = os.environ.copy()
    env['COVERAGE_PROCESS_START'] = '.coveragerc'
    
    cmd = [sys.executable, 'run_my_app.py']
    
    p  = subprocess.Popen(cmd, env=env)
    p.communicate()
    assert p.returncode == 0 # ..etc
    

    最后,您创建 .coveragerc 包含:

    [run]
    parallel = True
    source = myapp # Which module to collect coverage for
    

    这可确保每个进程创建的 .coverage 文件转到一个唯一文件,pytest-cov 似乎会自动合并该文件(或者可以使用 coverage combine 手动完成)。它还描述了为哪些模块收集数据(--cov=myapp arg 不会传递给子进程)

    要运行您的测试,只需调用 pytest --cov=

【讨论】:

以上是关于如何为基于 http 的集成测试生成覆盖率报告?的主要内容,如果未能解决你的问题,请参考以下文章

如何用PHPUnit生成代码覆盖率报告

Azure DevOps:如何为不同的测试(.net core、angular)合并两个代码覆盖率报告

Karma +Jasmine+ require JS进行单元测试并生成测试报告代码覆盖率报告

为单元和集成测试生成声纳覆盖率报告

在 gradle 中,如何为不同的任务创建单独的测试报告?

使用 Powermock 在 Sonarqube 中配置 jacoco 以进行集成和单元测试报告