首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >record_xml_property不适用于xdist

record_xml_property不适用于xdist
EN

Stack Overflow用户
提问于 2017-02-23 21:42:26
回答 1查看 264关注 0票数 0

我在测试中积极使用record_xml_property fixture,但不幸的是它不能与xdsit插件一起工作。我已经尝试实现了一种变通方法。我没有直接将属性添加到报告器中,而是将它们放到了从输出中:

代码语言:javascript
复制
@pytest.fixture
def record_xml_property(request):
    xml = getattr(request.config, "_xml", None)

    if xml is not None:
        node_reporter = xml.node_reporter(request.node.nodeid)
        return node_reporter.add_property

    else:
        def add_property_xdist(name, value):
            request.node.config.slaveoutput.update({'properties': {name: value}})

        return add_property_xdist

之后,我想在pytest_runtest_logreport钩子中将此属性添加到报告中:

代码语言:javascript
复制
@pytest.hookimpl(tryfirst=True)
def pytest_runtest_logreport(report):
    if report.when != 'teardown':
        return

    node = getattr(report, 'node', None)

    if not node:
        return

    xml = getattr(node.config, '_xml', None)

    if not xml:
        return

    node_reporter = xml.node_reporter(report)
    slaveoutput = getattr(node, 'slaveoutput', None)

    if not slaveoutput:
        return

    node_properties = slaveoutput.get('properties', {})

    for key, value in node_properties.items():
        node_reporter.add_property(key, value)

但问题是,在执行pytest_runtest_logreport钩子时,SlaveController对象中的从属输出通常还不可用。它在pytest_testnodedown中可用,SlaveInteractor将其与"slavefinished"事件一起发送,但目前报告已经定稿。有没有办法早点从从节点获取到从节点的输出?

EN

回答 1

Stack Overflow用户

发布于 2017-02-27 22:05:18

最后,我决定避免使用slaveoutput。我正在考虑一些涉及使用共享目录的解决方案,但最终我决定在主节点和从节点之间使用execnet通道。不幸的是,xdist的设计似乎不允许轻松地扩展主节点和从节点之间的通信。我不得不做一些补丁,代码复制和其他一些我不喜欢的讨厌的事情。但至少它是有效的。以下是我的解决方案:

代码语言:javascript
复制
@pytest.fixture
def record_xml_property(request):
    """
    Overrides original record_xml_property fixture from junitxml plugin
    """
    xml = getattr(request.config, "_xml", None)

    if xml is not None:
        node_reporter = xml.node_reporter(request.node.nodeid)
        return node_reporter.add_property
    else:
        pluginmanager = request.node.config.pluginmanager
        plugins = pluginmanager.get_plugins()
        slave_interactor = None

        for plugin in plugins:
            if plugin.__class__.__name__ == 'SlaveInteractor':
                slave_interactor = plugin

        if slave_interactor:
            # if test is running in slave node
            def add_property_xdist(name, value):
                slave_interactor.sendevent("record_xml_property", property=(name, value), nodeid=request.node.nodeid)

            return add_property_xdist

    def add_property_noop(name, value):
        pass

    return add_property_noop


def pytest_configure_node(node):
    xml = getattr(node.config, '_xml', None)

    if xml:
        # monkeypatching SlaveController right after it is created
        # process_from_remote is a callback function which is executed on channel event
        original_process_from_remote = node.process_from_remote

        def process_from_remote(self, eventcall):
            try:
                if eventcall != self.ENDMARK:
                    eventname, kwargs = eventcall

                    # In case of record_xml_property event, process it here. Otherwise process it in original
                    # process_from_remote function
                    if eventname == "record_xml_property":
                        self.log("recording xml property %s(%s)" % (eventname, kwargs))

                        # Report is not yet exists. I should use fake one to get proper reporter
                        class Fakereport:
                            def __init__(self, node, nodeid):
                                self.node = node
                                self.nodeid = nodeid

                        node_reporter = xml.node_reporter(Fakereport(self, kwargs['nodeid']))
                        name, value = kwargs['property']
                        node_reporter.add_property(name, value)
                        return
            except KeyboardInterrupt:
                # should not land in receiver-thread
                raise
            except:
                # the same except as in original process_from_remote method
                excinfo = py.code.ExceptionInfo()
                py.builtin.print_("!" * 20, excinfo)
                self.config.pluginmanager.notify_exception(excinfo)

            return original_process_from_remote(eventcall)

        node.process_from_remote = types.MethodType(process_from_remote, node)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42417453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档