javascript - 当用 python (pytest) 编写测试时,有没有办法实现 Nodejs 代码覆盖率?

标签 javascript python node.js code-coverage pytest

我在之前的项目中编写了 Mocha 测试。它的好处是 Istanbul 尔代码覆盖率工具。它非常有用而且很酷。 现在我正在为我当前的项目使用 pytest。有些服务是 Nodejs 应用程序。现在我的问题是,当我使用 pytest 时,有没有办法获得 Nodejs 应用程序的代码覆盖率?

最佳答案

结合istanbulcoverage工具的覆盖率报告有两个主要问题需要解决:

  1. 当然,coverage 对 javascript 文件一无所知,因此我们必须在覆盖率运行中以某种方式注册它们 - 这将通过实现自定义插件来完成。
  2. 我们必须将istanbul的覆盖率报告转换为coverage可以理解的格式。

设置

由于代码片段太大,无法直接放入答案中,所以我准备了一个git repository您可以使用以下命令重现测试运行(当然您可以根据需要重用代码):

$ git clone https://github.com/hoefling/stackoverflow-52124836
$ cd stackoverflow-52124836/
$ yarn install

首先生成 Istanbul 尔报道报告:

$ yarn test
  yarn run v1.9.4
  warning package.json: No license field
  $ istanbul cover _mocha js

  Array
    #length
      ✓ should be 0 when the array is empty
      ✓ should be 1 when the array has one element
      ✓ should be 2 when the array has two elements

  Array
    #indexOf()
      ✓ should return -1 when the value is not present


  4 passing (5ms)

=============================================================================
Writing coverage object [/private/tmp/stackoverflow-52124836/coverage/coverage.json]
Writing coverage reports at [/private/tmp/stackoverflow-52124836/coverage]
=============================================================================

=============================== Coverage summary ===============================
Statements   : 100% ( 14/14 )
Branches     : 100% ( 0/0 )
Functions    : 100% ( 8/8 )
Lines        : 100% ( 14/14 )
================================================================================

现在使用 pytest 运行 python 测试:

$ python -m pytest -sv --cov=py --cov=js --cov-report=term-missing
=================================== test session starts ===================================
platform darwin -- Python 3.6.4, pytest-3.7.3, py-1.5.4, pluggy-0.7.1 --
 /Users/hoefling/.virtualenvs/stackoverflow/bin/python
cachedir: .pytest_cache
rootdir: /private/tmp/stackoverflow-52124836, inifile:
plugins: cov-2.5.1
collected 1 item

py/test_spam.py::test_spam PASSED

---------- coverage: platform darwin, python 3.6.4-final-0 -----------
Name                      Stmts   Miss  Cover   Missing
-------------------------------------------------------
js/array.length.spec.js      14      0   100%
js/array.spec.js              8      0   100%
py/test_spam.py               2      0   100%
-------------------------------------------------------
TOTAL                        24      0   100%

================================ 1 passed in 0.56 seconds =================================

js/py 目录

这些只是一些可供使用的示例测试文件。为了简化设置,istanbul 收集测试代码的覆盖率。

mycov

包含覆盖插件。有关如何编写覆盖率插件的详细信息,请参阅 Plug-in classes ;这里我只是解释一下相关的地方:

class IstanbulPlugin(coverage.plugin.CoveragePlugin, coverage.plugin.FileTracer):

    def file_reporter(self, filename):
        return FileReporter(filename)

    def file_tracer(self, filename):
        return None

    def find_executable_files(self, src_dir):
        yield from (str(p) for p in pathlib.Path(src_dir).rglob('*.js')
                    if not any(d in p.parts for d in ('node_modules', 'coverage',)))

插件类除了搜索 javascript 文件并将它们注册为 coverage run(find_executable_files 方法)中的执行文件之外,什么也不做。它根本不记录代码覆盖率!它还为 javascript 文件注册一个简单的文件报告器 impl:

class FileReporter(coverage.plugin.FileReporter):

    def source(self):
        with open(self.filename) as fp:
            js = fp.read()
        return js

    def lines(self):
        return {i + 1 for i, line in enumerate(self.source().split(os.linesep)) if line.strip()}

记者按原样返回javascript文件的源代码,可执行行都是不为空的代码行。


注1:

这个 impl 还不够!例如,行和 block 注释行将被计为可执行文件。您需要调整lines方法;最好是使用一些 JavaScript 代码解析器来提取有关可执行行的信息。

注2:

istanbulcoverage 都从 1 开始计算行数,而不是从 0 开始计算行数,因此行号发生了变化。


现在您需要通过coverage_init注册插件:

# mycov/__init__.py

def coverage_init(reg, options):
    reg.add_file_tracer(IstanbulPlugin())

并在.coveragerc中添加自定义插件:

[run]
plugins = mycov

istanbul报告附加到coverage

现在 coverage 知道要考虑 javascript 文件,我们将把 js 覆盖率与 python 合并。 conftest.py 中的装置 append_istanbul_coverage 负责此操作。

@pytest.fixture(autouse=True)
def append_istanbul_coverage(cov):
    yield

    with open('coverage/coverage.json') as fp:
        data = json.load(fp)
    converted = {'lines': {item['path']: line_numbers(item) for item in data.values()}}
    text = "!coverage.py: This is a private format, don't read it directly!" + json.dumps(converted)
    istanbul_cov = coverage.data.CoverageData()

    with io.StringIO(text) as fp:
        istanbul_cov.read_fileobj(fp)
    cov.data.update(istanbul_cov)

每次测试运行时, fixture 将自动执行一次,当所有测试完成时,将运行 yield 之后的代码。 cov fixture由 pytest-cov 提供;我们用它来访问当前的覆盖数据对象。首先,我们阅读 Istanbul 尔的报道;然后将其转换为 coverage 可以理解的字符串 - 这只是普通的 json ,前面添加了特殊消息。之后,剩下的就是更新当前的覆盖范围数据,我们就完成了!

关于javascript - 当用 python (pytest) 编写测试时,有没有办法实现 Nodejs 代码覆盖率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52124836/

相关文章:

javascript - 使用 jquery/css 垂直对齐无衬线字体

javascript - 双击 Kendo Grid 行的 React Component

javascript - 从元素检索文本时未定义

php - 在 Python 和 PHP 上解密 AES256

python - numpy.savetxt 在标题行开头没有哈希标记

node.js - 在子数组上使用 "where"和 "in"时出现 Sequelize 错误

javascript - nodeJs大数组处理抛出RangeError : Maximum call stack size exceeded

跨多个类和文件的 Python 日志记录;如何配置才能轻松禁用?

node.js - 你能集中node_modules文件夹吗?

javascript - 如何使用 NodeJS 不断更新网页?