如何在pytest中集成自述文件的检查

时间:2017-10-16 09:03:39

标签: python travis-ci pytest

我在.travis.yml中使用pytest来检查我的代码。

我也想查看README.rst。

我通过此StackO readme_renderer

找到了answer

现在我问自己如何将其整合到我目前的测试中。

readme_renderer的文档提出了这个建议,但我还不知道如何将它集成到我的设置中:

python setup.py check -r -s

4 个答案:

答案 0 :(得分:4)

我认为最简单和最强大的选择是编写一个pytest插件,复制你在答案中提到的distutils command

这可能就像你的测试目录中的conftest.py一样简单。或者,如果你想要一个可以为我们所有人分发的独立插件,那么可以从中获益cookiecutter template

在调用pytest之后,在脚本部分手动调用检查本身并没有错。

答案 1 :(得分:4)

我现在这样检查:

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function

import os
import subx
import unittest

class Test(unittest.TestCase):
    def test_readme_rst_valid(self):
        base_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
subx.call(cmd=['python', os.path.join(base_dir, 'setup.py'), 'check', '--metadata', '--restructuredtext', '--strict'])

来源:https://github.com/guettli/reprec/blob/master/reprec/tests/test_setup.py

答案 2 :(得分:3)

所以我实现了一些东西,但确实需要一些修改。您需要修改setup.py,如下所示

from distutils.core import setup

setup_info = dict(
    name='so1',
    version='',
    packages=[''],
    url='',
    license='',
    author='tarun.lalwani',
    author_email='',
    description=''
)

if __name__ == "__main__":
    setup(**setup_info)

然后你需要创建一个符号链接,以便我们可以在测试中导入这个包

ln -s setup.py setup_mypackage.py

然后你可以创建一个如下所示的测试

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function

import os
import unittest
from distutils.command.check import check
from distutils.dist import Distribution

import setup_mypackage

class Test(unittest.TestCase):
    def test_readme_rst_valid(self):
        dist = Distribution(setup_mypackage.setup_info)
        test = check(dist)
        test.ensure_finalized()
        test.metadata = True
        test.strict = True
        test.restructuredtext = True

        global issues
        issues = []

        def my_warn(msg):
            global issues
            issues += [msg]
        test.warn = my_warn

        test.check_metadata()
        test.check_restructuredtext()

        if len(issues) > 0:
            assert len(issues) == 0, "\n".join(issues)

运行测试然后我得到

...
AssertionError: missing required meta-data: version, url
missing meta-data: if 'author' supplied, 'author_email' must be supplied too

Ran 1 test in 0.067s

FAILED (failures=1)

这是我能想到的一种可行的解决方法

答案 3 :(得分:2)

Upvoted,因为检查自述一致性是一件好事,我从未在我自己的项目中集成。从现在开始会做的!

我认为你调用check命令的方法很好,尽管它会检查更多自述文件的标记。 check将验证您的软件包的完整元数据,包括安装了readme_renderer的自述文件。

如果你想编写一个只进行标记检查的单元测试而没有其他内容,我会明确调用readme_renderer.rst.render

import pathlib
from readme_renderer.rst import render

def test_markup_is_generated():
    readme = pathlib.Path('README.rst')
    assert render(readme.read_text()) is not None

None检查是最基本的测试:如果render返回None,则表示自述文件包含错误,导致无法将其转换为HTML。如果您想要更细粒度的测试,请使用返回的HTML字符串。例如,我希望我的自述文件包含要强调的“扩展”一词:

import pathlib
import bs4
from readme_renderer.rst import render

def test_extensions_is_emphasized():
    readme = pathlib.Path('README.rst')
    html = render(readme.read_text())
    soup = bs4.BeautifulSoup(html)
    assert soup.find_all('em', string='extensions')

编辑:如果要查看已打印的警告,请使用可选的stream参数:

from io import StringIO

def test_markup_is_generated():
    warnings = StringIO()
    with open('README.rst') as f:
        html = render(f.read(), stream=warnings)
        warnings.seek(0)
        assert html is not None, warnings.read()

示例输出:

tests/test_readme.py::test_markup_is_generated FAILED
================ FAILURES ================
________ test_markup_is_generated ________

    def test_markup_is_generated():
        warnings = StringIO()
        with open('README.rst') as f:
            html = render(f.read(), stream=warnings)
            warnings.seek(0)
>           assert html is not None, warnings.read()
E           AssertionError: <string>:54: (WARNING/2) Title overline too short.
E             
E             ----
E             fffffff
E             ----
E             
E           assert None is not None

tests/test_readme.py:10: AssertionError
======== 1 failed in 0.26 seconds ========