zoukankan      html  css  js  c++  java
  • Robot Framework 源码阅读 day2 TestSuitBuilder

    接上一篇 day1 run.py

    发现build test suit还挺复杂的, 先从官网API找到了一些资料,可以看出这是robotframework进行组织

    测试案例实现的重要步骤, 将传入的testCase解析并生成suite对象, 等待调用

    https://robot-framework.readthedocs.io/en/v3.1/autodoc/robot.running.html

    (一)官网 API 说明部分

    robot.running package

    Implements the core test execution logic.

    The main public entry points of this package are of the following two classes:

    • TestSuiteBuilder for creating executable test suites based on existing test case files and directories.
    • TestSuiteBuilder 根据已有的测试文件和目录生成可执行的测试suites
    • TestSuite for creating an executable test suite structure programmatically.
    • TestSuite 根据传入参数生成可执行的测试suite
    • 两者区别是TestSuiteBuilder根据传入robotFramework的测试文件定义进行解析,然后生成可执行测试 suite
    • 而TestSuite是需要我们制定各种参数,生成可执行的测试 suite, TestSuiteBuilder解析之后回去调用TestSuite

    It is recommended to import both of these classes via the robot.api package like in the examples below. Also TestCase and Keyword classes used internally by the TestSuite class are part of the public API. In those rare cases where these classes are needed directly, they can be imported from this package.

    Examples

    First, let’s assume we have the following test suite in file activate_skynet.robot:

    1 *** Settings ***
    2 Library    OperatingSystem
    3 
    4 *** Test Cases ***
    5 Should Activate Skynet
    6     [Tags]    smoke
    7     [Setup]    Set Environment Variable    SKYNET    activated
    8     Environment Variable Should Be Set    SKYNET

    We can easily parse and create an executable test suite based on the above file using the TestSuiteBuilder class as follows:

    1 from robot.api import TestSuiteBuilder
    2 
    3 suite = TestSuiteBuilder().build('path/to/activate_skynet.robot')

    That was easy. Let’s next generate the same test suite from scratch using the TestSuite class:

    from robot.api import TestSuite
    
    suite = TestSuite('Activate Skynet')
    suite.resource.imports.library('OperatingSystem')
    test = suite.tests.create('Should Activate Skynet', tags=['smoke'])
    test.keywords.create('Set Environment Variable', args=['SKYNET', 'activated'], type='setup')
    test.keywords.create('Environment Variable Should Be Set', args=['SKYNET'])

    Not that complicated either, especially considering the flexibility. Notice that the suite created based on the file could also be edited further using the same API.

    Now that we have a test suite ready, let’s execute it and verify that the returned Result object contains correct information:

    result = suite.run(critical='smoke', output='skynet.xml')
    
    assert result.return_code == 0
    assert result.suite.name == 'Activate Skynet'
    test = result.suite.tests[0]
    assert test.name == 'Should Activate Skynet'
    assert test.passed and test.critical
    stats = result.suite.statistics
    assert stats.critical.total == 1 and stats.critical.failed == 0

    Running the suite generates a normal output XML file, unless it is disabled by using output=None. Generating log, report, and xUnit files based on the results is possible using the ResultWriter class:

    from robot.api import ResultWriter
    
    # Report and xUnit files can be generated based on the result object.
    ResultWriter(result).write_results(report='skynet.html', log=None)
    # Generating log files requires processing the earlier generated output XML.
    ResultWriter('skynet.xml').write_results()

    (二)代码阅读部分

    day1 的代码段,

    suite = TestSuiteBuilder(settings['SuiteNames'], settings['WarnOnSkipped']).build(*datasources)

    /robot/running/builder.py
    from .model import ForLoop, Keyword, ResourceFile, TestSuite

    def build(self, *paths): """ :param paths: Paths to test data files or directories. :return: :class:`~robot.running.model.TestSuite` instance. """ if not paths: raise DataError('One or more source paths required.') if len(paths) == 1: return self._parse_and_build(paths[0]) root = TestSuite() for path in paths: root.suites.append(self._parse_and_build(path)) return root

    主要功能在TestSuite() 的构建上, 生成TestSuite()实例

    *1*root = TestSuite()

    实例化之后 解析path传入的文件

    root.suites继承自父类 robot.model.testsuite.py, suites 返回TestSuites

    suites.append 即 TestSuites.append, 而TestSuites又继承自(ItemList)

    所以调用TtemList.append

    robot.model.testsuite.py

    *2*root.suites.append(self._parse_and_build(path))
    --->
        @setter
        def suites(self, suites):
            """Child suites as a :class:`~.TestSuites` object."""
            return TestSuites(self.__class__, self, suites)
    
        class TestSuites(ItemList):
            __slots__ = []
    
            def __init__(self, suite_class=TestSuite, parent=None, suites=None):
                ItemList.__init__(self, suite_class, {'parent': parent}, suites) #初始化父类
    @py2to3
    class ItemList(object):
        __slots__ = ['_item_class', '_common_attrs', '_items']
    
        def __init__(self, item_class, common_attrs=None, items=None):
            self._item_class = item_class
            self._common_attrs = common_attrs
            self._items = ()
            if items:
                self.extend(items)
    
        def create(self, *args, **kwargs):
            return self.append(self._item_class(*args, **kwargs))
    
        def append(self, item):
            self._check_type_and_set_attrs(item)
            self._items += (item,)
            return item

    _build_suite
    构建文件中的每个suite, 然后填入list中待执行, 详细见_build_suite这块代码解析
    下面三个函数进行了suite的具体构建, setup/teardown/test, 每个suite的三元素进行了构建
    _build_setup
    (suite, data.setting_table.suite_setup) _build_teardown(suite, data.setting_table.suite_teardown) _build_test(suite, test_data, defaults)
    *3*self._parse_and_build(path)
    
    
        def _parse_and_build(self, path):
        suite = self._build_suite(self._parse(path))
        suite.remove_empty_suites()
        return suite
    
    
    from robot.parsing import TestData, ResourceFile as ResourceData    

    def _parse(self, path): try: return TestData(source=abspath(path), include_suites=self.include_suites, warn_on_skipped=self.warn_on_skipped) except DataError as err: raise DataError("Parsing '%s' failed: %s" % (path, err.message))
        def _build_suite(self, data, parent_defaults=None):
         #根据传入的data进行 test suite 构建
    defaults
    = TestDefaults(data.setting_table, parent_defaults) suite = TestSuite(name=data.name, # 传入data.name ... 下同 source=data.source, doc=unic(data.setting_table.doc), metadata=self._get_metadata(data.setting_table)) self._build_setup(suite, data.setting_table.suite_setup) self._build_teardown(suite, data.setting_table.suite_teardown) for test_data in data.testcase_table.tests: self._build_test(suite, test_data, defaults) for child in data.children: suite.suites.append(self._build_suite(child, defaults)) ResourceFileBuilder().build(data, target=suite.resource) return suite
     

    running 中的 TestSuite 继承自 robot.model.TestSuite

    class TestSuite(model.TestSuite):
        """Represents a single executable test suite.
    
        See the base class for documentation of attributes not documented here.
        """
        __slots__ = ['resource']
        test_class = TestCase    #: Internal usage only.
        keyword_class = Keyword  #: Internal usage only.
    
        def __init__(self,  name='', doc='', metadata=None, source=None):
            model.TestSuite.__init__(self, name, doc, metadata, source) 
            #: :class:`ResourceFile` instance containing imports, variables and
            #: keywords the suite owns. When data is parsed from the file system,
            #: this data comes from the same test case file that creates the suite.
            self.resource = ResourceFile(source=source)

    脑瓜疼, 看不下去了, 休息一会儿 。。。 。。。

  • 相关阅读:
    vmware安装ubuntu
    加快pip install的速度
    在Dataframe中寻找特定值所在行的行号
    后续:尝试交易策略
    小实验:股票涨幅日间的相关性
    大数据之数据预处理
    并查集
    2020华为杯数学建模B题-RON建模 赛后总结与分析
    二叉树的遍历总结
    几数之和分析,解法,优化和总结
  • 原文地址:https://www.cnblogs.com/brownz/p/10235179.html
Copyright © 2011-2022 走看看