From 2eb87a8743ff0adc8d7cd2879459088d2a887bab Mon Sep 17 00:00:00 2001 From: Rene Date: Fri, 27 Aug 2021 23:22:59 +0200 Subject: [PATCH] updated Doc --- Readme.rst | 6 +- atest/TestCases/Tags/foo_reader.py | 1 - create_readme.py | 3 +- doc/DataDriver.html | 2 +- src/DataDriver/DataDriver.py | 1988 ++++++++++++++-------------- src/DataDriver/utils.py | 74 +- src/DataDriver/xls_reader.py | 6 +- 7 files changed, 1042 insertions(+), 1038 deletions(-) diff --git a/Readme.rst b/Readme.rst index 9dac766..8d78b8d 100644 --- a/Readme.rst +++ b/Readme.rst @@ -1,5 +1,3 @@ - - =================================================== DataDriver for Robot Framework® =================================================== @@ -1267,6 +1265,4 @@ Binary creates with 40 test cases and 8 threads something like that: P13: 37 P14: 38 P15: 39 - P16: 40 - - \ No newline at end of file + P16: 40 \ No newline at end of file diff --git a/atest/TestCases/Tags/foo_reader.py b/atest/TestCases/Tags/foo_reader.py index 4b7bba2..5802bd8 100644 --- a/atest/TestCases/Tags/foo_reader.py +++ b/atest/TestCases/Tags/foo_reader.py @@ -3,7 +3,6 @@ class foo_reader(AbstractReaderClass): - def get_data_from_source(self): return self._read_file_to_data_table() diff --git a/create_readme.py b/create_readme.py index 63efc59..3c271d9 100644 --- a/create_readme.py +++ b/create_readme.py @@ -1,5 +1,6 @@ from DataDriver import DataDriver +from inspect import getdoc with open("Readme.rst", "w", encoding="utf-8") as readme: - doc_string = DataDriver.__doc__ + doc_string = getdoc(DataDriver) readme.write(str(doc_string).replace("\\", "\\\\").replace("\\\\*", "\\*")) diff --git a/doc/DataDriver.html b/doc/DataDriver.html index 92498e1..7e4537e 100644 --- a/doc/DataDriver.html +++ b/doc/DataDriver.html @@ -1101,7 +1101,7 @@ jQuery.extend({highlight:function(e,t,n,r){if(e.nodeType===3){var i=e.data.match(t);if(i){var s=document.createElement(n||"span");s.className=r||"highlight";var o=e.splitText(i.index);o.splitText(i[0].length);var u=o.cloneNode(true);s.appendChild(u);o.parentNode.replaceChild(s,o);return 1}}else if(e.nodeType===1&&e.childNodes&&!/(script|style)/i.test(e.tagName)&&!(e.tagName===n.toUpperCase()&&e.className===r)){for(var a=0;a diff --git a/src/DataDriver/DataDriver.py b/src/DataDriver/DataDriver.py index 7d70b06..f27a60c 100644 --- a/src/DataDriver/DataDriver.py +++ b/src/DataDriver/DataDriver.py @@ -44,7 +44,8 @@ error, equally_partition_test_list, binary_partition_test_list, - Encodings, TagHandling, + Encodings, + TagHandling, ) __version__ = "1.5.0" @@ -54,1277 +55,1277 @@ class DataDriver: # region: docstring """ -=================================================== -DataDriver for Robot Framework® -=================================================== + =================================================== + DataDriver for Robot Framework® + =================================================== -DataDriver is a Data-Driven extension for Robot Framework®. -This document explains how to use the DataDriver library listener. For -information about installation, support, and more, please visit the -`project page `_ + DataDriver is a Data-Driven extension for Robot Framework®. + This document explains how to use the DataDriver library listener. For + information about installation, support, and more, please visit the + `project page `_ -For more information about Robot Framework®, see http://robotframework.org. + For more information about Robot Framework®, see http://robotframework.org. -DataDriver is used/imported as Library but does not provide keywords -which can be used in a test. DataDriver uses the Listener Interface -Version 3 to manipulate the test cases and creates new test cases based -on a Data-File that contains the data for Data-Driven Testing. These -data file may be .csv , .xls or .xlsx files. + DataDriver is used/imported as Library but does not provide keywords + which can be used in a test. DataDriver uses the Listener Interface + Version 3 to manipulate the test cases and creates new test cases based + on a Data-File that contains the data for Data-Driven Testing. These + data file may be .csv , .xls or .xlsx files. -Data Driver is also able to cooperate with Microsoft PICT. An Open -Source Windows tool for data combination testing. Pict is able to -generate data combinations based on textual model definitions. -https://github.com/Microsoft/pict + Data Driver is also able to cooperate with Microsoft PICT. An Open + Source Windows tool for data combination testing. Pict is able to + generate data combinations based on textual model definitions. + https://github.com/Microsoft/pict -It is also possible to implement own DataReaders in Python to read -your test data from some other sources, like databases or json files. + It is also possible to implement own DataReaders in Python to read + your test data from some other sources, like databases or json files. -Installation ------------- + Installation + ------------ -If you already have Python >= 3.6 with pip installed, you can simply -run: + If you already have Python >= 3.6 with pip installed, you can simply + run: -``pip install --upgrade robotframework-datadriver`` + ``pip install --upgrade robotframework-datadriver`` -Excel Support -~~~~~~~~~~~~~ + Excel Support + ~~~~~~~~~~~~~ -For file support of ``xls`` or ``xlsx`` file you need to install the extra XLS or the dependencies. -It contains the dependencies of pandas, numpy and xlrd. Just add [XLS] to your installation. -New since version 3.6. + For file support of ``xls`` or ``xlsx`` file you need to install the extra XLS or the dependencies. + It contains the dependencies of pandas, numpy and xlrd. Just add [XLS] to your installation. + New since version 3.6. -``pip install --upgrade robotframework-datadriver[XLS]`` + ``pip install --upgrade robotframework-datadriver[XLS]`` -Python 2 -~~~~~~~~ + Python 2 + ~~~~~~~~ -or if you have Python 2 and 3 installed in parallel you may use + or if you have Python 2 and 3 installed in parallel you may use -``pip3 install --upgrade robotframework-datadriver`` + ``pip3 install --upgrade robotframework-datadriver`` -DataDriver is compatible with Python 2.7 only in Version 0.2.7. + DataDriver is compatible with Python 2.7 only in Version 0.2.7. -``pip install --upgrade robotframework-datadriver==0.2.7`` + ``pip install --upgrade robotframework-datadriver==0.2.7`` -Because Python 2.7 is deprecated, there are no new feature to python 2.7 compatible version. + Because Python 2.7 is deprecated, there are no new feature to python 2.7 compatible version. -Table of contents ------------------ + Table of contents + ----------------- -- `What DataDriver Does`_ -- `How DataDriver Works`_ -- `Usage`_ -- `Structure of Test Suite`_ -- `Structure of data file`_ -- `Accessing Test Data From Robot Variables`_ -- `Data Sources`_ -- `File Encoding and CSV Dialect`_ -- `Custom DataReader Classes`_ -- `Selection of Test Cases to Execute`_ -- `Configure DataDriver by Pre-Run Keyword`_ -- `Pabot and DataDriver`_ + - `What DataDriver Does`_ + - `How DataDriver Works`_ + - `Usage`_ + - `Structure of Test Suite`_ + - `Structure of data file`_ + - `Accessing Test Data From Robot Variables`_ + - `Data Sources`_ + - `File Encoding and CSV Dialect`_ + - `Custom DataReader Classes`_ + - `Selection of Test Cases to Execute`_ + - `Configure DataDriver by Pre-Run Keyword`_ + - `Pabot and DataDriver`_ -What DataDriver Does --------------------- + What DataDriver Does + -------------------- -DataDriver is an alternative approach to create Data-Driven Tests with -Robot Framework®. DataDriver creates multiple test cases based on a test -template and data content of a csv or Excel file. All created tests -share the same test sequence (keywords) and differ in the test data. -Because these tests are created on runtime only the template has to be -specified within the robot test specification and the used data are -specified in an external data file. + DataDriver is an alternative approach to create Data-Driven Tests with + Robot Framework®. DataDriver creates multiple test cases based on a test + template and data content of a csv or Excel file. All created tests + share the same test sequence (keywords) and differ in the test data. + Because these tests are created on runtime only the template has to be + specified within the robot test specification and the used data are + specified in an external data file. -RoboCon 2020 Talk -~~~~~~~~~~~~~~~~~ + RoboCon 2020 Talk + ~~~~~~~~~~~~~~~~~ -.. image:: https://img.youtube.com/vi/RtEUr1i4x3s/0.jpg - :target: https://www.youtube.com/watch?v=RtEUr1i4x3s + .. image:: https://img.youtube.com/vi/RtEUr1i4x3s/0.jpg + :target: https://www.youtube.com/watch?v=RtEUr1i4x3s -Brief overview what DataDriver is and how it works at the RoboCon 2020 in Helsiki. + Brief overview what DataDriver is and how it works at the RoboCon 2020 in Helsiki. -Alternative approach -~~~~~~~~~~~~~~~~~~~~ + Alternative approach + ~~~~~~~~~~~~~~~~~~~~ -DataDriver gives an alternative to the build in data driven approach -like: + DataDriver gives an alternative to the build in data driven approach + like: -.. code :: robotframework + .. code :: robotframework - *** Settings *** - Resource login_resources.robot + *** Settings *** + Resource login_resources.robot - Suite Setup Open my Browser - Suite Teardown Close Browsers - Test Setup Open Login Page - Test Template Invalid login + Suite Setup Open my Browser + Suite Teardown Close Browsers + Test Setup Open Login Page + Test Template Invalid login - *** Test Cases *** User Passwort - Right user empty pass demo ${EMPTY} - Right user wrong pass demo FooBar + *** Test Cases *** User Passwort + Right user empty pass demo ${EMPTY} + Right user wrong pass demo FooBar - Empty user right pass ${EMPTY} mode - Empty user empty pass ${EMPTY} ${EMPTY} - Empty user wrong pass ${EMPTY} FooBar + Empty user right pass ${EMPTY} mode + Empty user empty pass ${EMPTY} ${EMPTY} + Empty user wrong pass ${EMPTY} FooBar - Wrong user right pass FooBar mode - Wrong user empty pass FooBar ${EMPTY} - Wrong user wrong pass FooBar FooBar + Wrong user right pass FooBar mode + Wrong user empty pass FooBar ${EMPTY} + Wrong user wrong pass FooBar FooBar - *** Keywords *** - Invalid login - [Arguments] ${username} ${password} - Input username ${username} - Input pwd ${password} - click login button - Error page should be visible + *** Keywords *** + Invalid login + [Arguments] ${username} ${password} + Input username ${username} + Input pwd ${password} + click login button + Error page should be visible -This inbuilt approach is fine for a hand full of data and a hand full of -test cases. If you have generated or calculated data and specially if -you have a variable amount of test case / combinations these robot files -become quite a pain. With DataDriver you may write the same test case -syntax but only once and deliver the data from en external data file. + This inbuilt approach is fine for a hand full of data and a hand full of + test cases. If you have generated or calculated data and specially if + you have a variable amount of test case / combinations these robot files + become quite a pain. With DataDriver you may write the same test case + syntax but only once and deliver the data from en external data file. -One of the rare reasons when Microsoft® Excel or LibreOffice Calc may be -used in testing… ;-) + One of the rare reasons when Microsoft® Excel or LibreOffice Calc may be + used in testing… ;-) -`See example test suite <#example-suite>`__ + `See example test suite <#example-suite>`__ -`See example csv table <#example-csv>`__ + `See example csv table <#example-csv>`__ -How DataDriver Works --------------------- + How DataDriver Works + -------------------- -When the DataDriver is used in a test suite it will be activated before -the test suite starts. It uses the Listener Interface Version 3 of Robot -Framework® to read and modify the test specification objects. After -activation it searches for the ``Test Template`` -Keyword to analyze the -``[Arguments]`` it has. As a second step, it loads the data from the -specified data source. Based on the ``Test Template`` -Keyword, DataDriver -creates as much test cases as data sets are in the data source. + When the DataDriver is used in a test suite it will be activated before + the test suite starts. It uses the Listener Interface Version 3 of Robot + Framework® to read and modify the test specification objects. After + activation it searches for the ``Test Template`` -Keyword to analyze the + ``[Arguments]`` it has. As a second step, it loads the data from the + specified data source. Based on the ``Test Template`` -Keyword, DataDriver + creates as much test cases as data sets are in the data source. -In the case that data source is csv (Default) -As values for the arguments of the ``Test Template`` -Keyword, DataDriver -reads values from the column of the CSV file with the matching name of the -``[Arguments]``. -For each line of the CSV data table, one test case will be created. It -is also possible to specify test case names, tags and documentation for -each test case in the specific test suite related CSV file. + In the case that data source is csv (Default) + As values for the arguments of the ``Test Template`` -Keyword, DataDriver + reads values from the column of the CSV file with the matching name of the + ``[Arguments]``. + For each line of the CSV data table, one test case will be created. It + is also possible to specify test case names, tags and documentation for + each test case in the specific test suite related CSV file. -Usage ------ + Usage + ----- -Data Driver is a "Library Listener" but does not provide keywords. -Because Data Driver is a listener and a library at the same time it -sets itself as a listener when this library is imported into a test suite. + Data Driver is a "Library Listener" but does not provide keywords. + Because Data Driver is a listener and a library at the same time it + sets itself as a listener when this library is imported into a test suite. -To use it, just use it as Library in your suite. You may use the first -argument (option) which may set the file name or path to the data file. + To use it, just use it as Library in your suite. You may use the first + argument (option) which may set the file name or path to the data file. -Without any options set, it loads a .csv file which has the same name -and path like the test suite .robot . + Without any options set, it loads a .csv file which has the same name + and path like the test suite .robot . -**Example:** + **Example:** -.. code :: robotframework + .. code :: robotframework - *** Settings *** - Library DataDriver - Test Template Invalid Logins + *** Settings *** + Library DataDriver + Test Template Invalid Logins - *** Keywords *** - Invalid Logins - ... + *** Keywords *** + Invalid Logins + ... -Structure of Test Suite ------------------------ + Structure of Test Suite + ----------------------- -Requirements -~~~~~~~~~~~~ + Requirements + ~~~~~~~~~~~~ -In the Moment there are some requirements how a test -suite must be structured so that the DataDriver can get all the -information it needs. + In the Moment there are some requirements how a test + suite must be structured so that the DataDriver can get all the + information it needs. + + - only the first test case will be used as a template. All other test + cases will be deleted. + - Test cases have to be defined with a + ``Test Template`` in Settings secion. Reason for this is, + that the DataDriver needs to know the names of the test case arguments. + Test cases do not have named arguments. Keywords do. + - The keyword which is used as + ``Test Template`` must be defined within the test suite (in the same + \*.robot file). If the keyword which is used as ``Test Template`` is + defined in a ``Resource`` the DataDriver has no access to its + arguments names. + + + Example Test Suite + ~~~~~~~~~~~~~~~~~~ + + .. code :: robotframework + + ***Settings*** + Library DataDriver + Resource login_resources.robot + Suite Setup Open my Browser + Suite Teardown Close Browsers + Test Setup Open Login Page + Test Template Invalid Login + + *** Test Case *** + Login with user ${username} and password ${password} Default UserData + + ***** *Keywords* ***** + Invalid login + [Arguments] ${username} ${password} + Input username ${username} + Input pwd ${password} + click login button + Error page should be visible + + In this example, the DataDriver is activated by using it as a Library. + It is used with default settings. + As ``Test Template`` the keyword ``Invalid Login`` is used. This + keyword has two arguments. Argument names are ``${username}`` and + ``${password}``. These names have to be in the CSV file as column + header. The test case has two variable names included in its name, + which does not have any functionality in Robot Framework®. However, the + Data Driver will use the test case name as a template name and + replaces the variables with the specific value of the single generated + test case. + This template test will only be used as a template. The specified data + ``Default`` and ``UserData`` would only be used if no CSV file has + been found. + + + Structure of data file + ---------------------- + + + min. required columns + ~~~~~~~~~~~~~~~~~~~~~ - - only the first test case will be used as a template. All other test - cases will be deleted. - - Test cases have to be defined with a - ``Test Template`` in Settings secion. Reason for this is, - that the DataDriver needs to know the names of the test case arguments. - Test cases do not have named arguments. Keywords do. - - The keyword which is used as - ``Test Template`` must be defined within the test suite (in the same - \*.robot file). If the keyword which is used as ``Test Template`` is - defined in a ``Resource`` the DataDriver has no access to its - arguments names. + - ``*** Test Cases ***`` column has to be the first one. + - *Argument columns:* For each argument of the ``Test Template`` + keyword one column must be existing in the data file as data source. + The name of this column must match the variable name and syntax. + + + optional columns + ~~~~~~~~~~~~~~~~ + - *[Tags]* column may be used to add specific tags to a test case. Tags + may be comma separated. + - *[Documentation]* column may be used to add specific test case + documentation. + + + Example Data file + ~~~~~~~~~~~~~~~~~ + + +-------------+-------------+-------------+-------------+------------------+ + | \**\* Test | ${username} | ${password} | [Tags] | [Documentation] | + | Cases \**\* | | | | | + | | | | | | + +=============+=============+=============+=============+==================+ + | Right user | demo | ${EMPTY} | 1 | This is a test | + | empty pass | | | | case | + | | | | | documentation of | + | | | | | the first one. | + +-------------+-------------+-------------+-------------+------------------+ + | Right user | demo | FooBar | 2,3,foo | This test | + | wrong pass | | | | case has | + | | | | | the Tags | + | | | | | 2,3 and foo | + | | | | | assigned. | + +-------------+-------------+-------------+-------------+------------------+ + | | ${EMPTY} | mode | 1,2,3,4 | This test | + | | | | | case has a | + | | | | | generated | + | | | | | name based | + | | | | | on template | + | | | | | name. | + +-------------+-------------+-------------+-------------+------------------+ + | | ${EMPTY} | ${EMPTY} | | | + +-------------+-------------+-------------+-------------+------------------+ + | | ${EMPTY} | FooBar | | | + +-------------+-------------+-------------+-------------+------------------+ + | | FooBar | mode | | | + +-------------+-------------+-------------+-------------+------------------+ + | | FooBar | ${EMPTY} | | | + +-------------+-------------+-------------+-------------+------------------+ + | | FooBar | FooBar | | | + +-------------+-------------+-------------+-------------+------------------+ + + In this data file, eight test cases are defined. Each line specifies one + test case. The first two test cases have specific names. The other six + test cases will generate names based on template test cases name with + the replacement of variables in this name. The order of columns is + irrelevant except the first column, ``*** Test Cases ***`` + + Supported Data Types + ~~~~~~~~~~~~~~~~~~~~ + + In general DataDriver supports any Object that is handed over from the DataReader. + However the text based readers for csv, excel and so do support different types as well. + DataDriver supports Robot Framework® Scalar variables as well as Dictionaries and Lists. + It also support python literal evaluations. + + Scalar Variables + ^^^^^^^^^^^^^^^^ + + The Prefix ``$`` defines that the value in the cell is taken as in Robot Framework® Syntax. + ``String`` is ``str``, ``${1}`` is ``int`` and ``${None}`` is NoneType. + The Prefix only defines the value typ. It can also be used to assign a scalar to a dictionary key. + See example table: ``${user}[id]`` + + + Dictionary Variables + ^^^^^^^^^^^^^^^^^^^^ + + Dictionaries can be created in different ways. + + One option is, to use the prefix ``&``. + If a variable is defined that was (i.e. ``&{dict}``) the cell value is interpreted the same way, + the BuiltIn keyword `Create Dictionary `_ would do. + The arguments here are comma (``,``) separated. + See example table: ``&{dict}`` + + The other option is to define scalar variables in dictionary syntax like ``${user}[name]`` or ``${user.name}`` + That can be also nested dictionaries. DataDriver will create Robot Framework® (DotDict) Dictionaries, that can be accessed with ``${user.name.first}`` + See example table: ``${user}[name][first]`` + + + List Variables + ^^^^^^^^^^^^^^ + + Lists can be created with the prefix ``@`` as comma (``,``) separated list. + See example table: ``@{list}`` + + Be aware that a list with an empty string has to be the cell content `${Empty}`. + + Python Literals + ^^^^^^^^^^^^^^^ + + DataDriver can evaluate Literals. + It uses the prefix ``e`` for that. (i.e. ``e{list_eval}``) + For that it uses `BuiltIn Evaluate `_ + + See example table: ``e{user.chk}`` + + + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``*** Test Cases ***`` | ``${scalar}`` | ``@{list}`` | ``e{list_eval}`` | ``&{dict}`` | ``e{dict_eval}`` | ``e{eval}`` | ``${exp_eval}`` | ``${user}[id]`` | ``${user}[name][first]`` | ``${user.name.last}`` | ``e{user.chk}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``One`` | ``Sum List`` | ``1,2,3,4`` | ``["1","2","3","4"]`` | ``key=value`` | ``{'key': 'value'}`` | ``[1,2,3,4]`` | ``10`` | ``1`` | ``Pekka`` | ``Klärck`` | ``{'id': '1', 'name': {'first': 'Pekka', 'last': 'Klärck'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``Two`` | ``Should be Equal`` | ``a,b,c,d`` | ``["a","b","c","d"]`` | ``key,value`` | ``{'key': 'value'}`` | ``True`` | ``${true}`` | ``2`` | ``Ed`` | ``Manlove`` | ``{'id': '2', 'name': {'first': 'Ed', 'last': 'Manlove'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``Three`` | ``Whos your Daddy`` | ``!,",',$`` | ``["!",'"',"'","$"]`` | ``z,value,a,value2`` | ``{'a': 'value2', 'z': 'value'}`` | ``{'Daddy' : 'René'}`` | ``René`` | ``3`` | ``Tatu`` | ``Aalto`` | ``{'id': '3', 'name': {'first': 'Tatu', 'last': 'Aalto'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``4`` | ``Should be Equal`` | ``1`` | ``["1"]`` | ``key=value`` | ``{'key': 'value'}`` | ``1`` | ``${1}`` | ``4`` | ``Jani`` | ``Mikkonen`` | ``{'id': '4', 'name': {'first': 'Jani', 'last': 'Mikkonen'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``5`` | ``Should be Equal`` | | ``[]`` | ``a=${2}`` | ``{'a':2}`` | ``"string"`` | ``string`` | ``5`` | ``Mikko`` | ``Korpela`` | ``{'id': '5', 'name': {'first': 'Mikko', 'last': 'Korpela'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + | ``6`` | ``Should be Equal`` | ``[1,2]`` | ``["[1","2]"]`` | ``key=value,key2=value2`` | ``{'key': 'value', 'key2': 'value2'}`` | ``None`` | ``${none}`` | ``6`` | ``Ismo`` | ``Aro`` | ``{'id': '6', 'name': {'first': 'Ismo', 'last': 'Aro'}}`` | + +--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ + + + Accessing Test Data From Robot Variables + ---------------------------------------- + + If neccesary it is possible to access the fetched data tables directly from a Robot Framework® variable. + This could be helpfull in Test Setup or in Suite Setup. + + There are three variables available within the Data-Driven Suite: + + @{DataDriver_DATA_LIST} + ~~~~~~~~~~~~~~~~~~~~~~~ + + A list as suite variable containing a robot dictionary for each test case that is selected for execution. + + .. code :: json + + [ + { + "test_case_name": "Right user empty pass", + "arguments": { + "${username}": "demo", + "${password}": "${EMPTY}" + }, + "tags": [ + "1" + ], + "documentation": "This is a test case documentation of the first one." + }, + { + "test_case_name": "Right user wrong pass", + "arguments": { + "${username}": "demo", + "${password}": "FooBar" + }, + "tags": [ + "2", + "3", + "foo" + ], + "documentation": "This test case has the Tags 2,3 and foo" + }, + { + "test_case_name": "Login with user '${EMPTY}' and password 'mode'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "mode" + }, + "tags": [ + "1", + "2", + "3", + "4" + ], + "documentation": "This test case has a generated name based on template name." + }, + { + "test_case_name": "Login with user '${EMPTY}' and password '${EMPTY}'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "${EMPTY}" + }, + "tags": [ + "" + ], + "documentation": "" + }, + { + "test_case_name": "Login with user '${EMPTY}' and password 'FooBar'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "FooBar" + }, + "tags": [ + "" + ], + "documentation": "" + }, + { + "test_case_name": "Login with user 'FooBar' and password 'mode'", + "arguments": { + "${username}": "FooBar", + "${password}": "mode" + }, + "tags": [ + "foo", + "1" + ], + "documentation": "" + }, + { + "test_case_name": "Login with user 'FooBar' and password '${EMPTY}'", + "arguments": { + "${username}": "FooBar", + "${password}": "${EMPTY}" + }, + "tags": [ + "foo" + ], + "documentation": "" + }, + { + "test_case_name": "Login with user 'FooBar' and password 'FooBar'", + "arguments": { + "${username}": "FooBar", + "${password}": "FooBar" + }, + "tags": [ + "foo", + "2" + ], + "documentation": "" + } + ] + + This can be accessed as usual in Robot Framework®. + + ``${DataDriver_DATA_LIST}[2][arguments][\${password}]`` would result in ``mode`` . + + + + &{DataDriver_DATA_DICT} + ~~~~~~~~~~~~~~~~~~~~~~~ + + A dictionary as suite variable that contains the same data as the list, with the test names as keys. + + .. code :: json + + { + "Right user empty pass": { + "test_case_name": "Right user empty pass", + "arguments": { + "${username}": "demo", + "${password}": "${EMPTY}" + }, + "tags": [ + "1" + ], + "documentation": "This is a test case documentation of the first one." + }, + "Right user wrong pass": { + "test_case_name": "Right user wrong pass", + "arguments": { + "${username}": "demo", + "${password}": "FooBar" + }, + "tags": [ + "2", + "3", + "foo" + ], + "documentation": "This test case has the Tags 2,3 and foo" + }, + "Login with user '${EMPTY}' and password 'mode'": { + "test_case_name": "Login with user '${EMPTY}' and password 'mode'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "mode" + }, + "tags": [ + "1", + "2", + "3", + "4" + ], + "documentation": "This test case has a generated name based on template name." + }, + "Login with user '${EMPTY}' and password '${EMPTY}'": { + "test_case_name": "Login with user '${EMPTY}' and password '${EMPTY}'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "${EMPTY}" + }, + "tags": [ + "" + ], + "documentation": "" + }, + "Login with user '${EMPTY}' and password 'FooBar'": { + "test_case_name": "Login with user '${EMPTY}' and password 'FooBar'", + "arguments": { + "${username}": "${EMPTY}", + "${password}": "FooBar" + }, + "tags": [ + "" + ], + "documentation": "" + }, + "Login with user 'FooBar' and password 'mode'": { + "test_case_name": "Login with user 'FooBar' and password 'mode'", + "arguments": { + "${username}": "FooBar", + "${password}": "mode" + }, + "tags": [ + "foo", + "1" + ], + "documentation": "" + }, + "Login with user 'FooBar' and password '${EMPTY}'": { + "test_case_name": "Login with user 'FooBar' and password '${EMPTY}'", + "arguments": { + "${username}": "FooBar", + "${password}": "${EMPTY}" + }, + "tags": [ + "foo" + ], + "documentation": "" + }, + "Login with user 'FooBar' and password 'FooBar'": { + "test_case_name": "Login with user 'FooBar' and password 'FooBar'", + "arguments": { + "${username}": "FooBar", + "${password}": "FooBar" + }, + "tags": [ + "foo", + "2" + ], + "documentation": "" + } + } + + &{DataDriver_TEST_DATA} + ~~~~~~~~~~~~~~~~~~~~~~~ + + A dictionary as test variable that contains the test data of the current test case. + This dictionary does also contain arguments that are not used in the ``Test Template`` keyword. + This can be used in Test Setup and within a test case. + + .. code :: json + + { + "test_case_name": "Right user wrong pass", + "arguments": { + "${username}": "demo", + "${password}": "FooBar" + }, + "tags": [ + "2", + "3", + "foo" + ], + "documentation": "This test case has the Tags 2,3 and foo" + } + + + Data Sources + ------------ + + + CSV / TSV (Character-separated values) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + By default DataDriver reads csv files. With the `Encoding and CSV + Dialect <#file-encoding-and-csv-dialect>`__ settings you may configure which + structure your data source has. + + + XLS / XLSX Files + ~~~~~~~~~~~~~~~~ + + To use Excel file types, you have to install DataDriver with the Extra XLS. + + If you want to use Excel based data sources, you may just set the file + to the extention or you may point to the correct file. If the extention + is ".xls" or ".xlsx" DataDriver will interpret it as Excel file. + You may select the sheet which will be read by the option ``sheet_name``. + By default it is set to 0 which will be the first table sheet. + You may use sheet index (0 is first sheet) or sheet name(case sensitive). + XLS interpreter will ignore all other options like encoding, delimiters etc. + + .. code :: robotframework -Example Test Suite -~~~~~~~~~~~~~~~~~~ - -.. code :: robotframework - - ***Settings*** - Library DataDriver - Resource login_resources.robot - Suite Setup Open my Browser - Suite Teardown Close Browsers - Test Setup Open Login Page - Test Template Invalid Login - - *** Test Case *** - Login with user ${username} and password ${password} Default UserData - - ***** *Keywords* ***** - Invalid login - [Arguments] ${username} ${password} - Input username ${username} - Input pwd ${password} - click login button - Error page should be visible - -In this example, the DataDriver is activated by using it as a Library. -It is used with default settings. -As ``Test Template`` the keyword ``Invalid Login`` is used. This -keyword has two arguments. Argument names are ``${username}`` and -``${password}``. These names have to be in the CSV file as column -header. The test case has two variable names included in its name, -which does not have any functionality in Robot Framework®. However, the -Data Driver will use the test case name as a template name and -replaces the variables with the specific value of the single generated -test case. -This template test will only be used as a template. The specified data -``Default`` and ``UserData`` would only be used if no CSV file has -been found. - - -Structure of data file ----------------------- - - -min. required columns -~~~~~~~~~~~~~~~~~~~~~ - -- ``*** Test Cases ***`` column has to be the first one. -- *Argument columns:* For each argument of the ``Test Template`` - keyword one column must be existing in the data file as data source. - The name of this column must match the variable name and syntax. - - -optional columns -~~~~~~~~~~~~~~~~ - -- *[Tags]* column may be used to add specific tags to a test case. Tags - may be comma separated. -- *[Documentation]* column may be used to add specific test case - documentation. - - -Example Data file -~~~~~~~~~~~~~~~~~ - -+-------------+-------------+-------------+-------------+------------------+ -| \**\* Test | ${username} | ${password} | [Tags] | [Documentation] | -| Cases \**\* | | | | | -| | | | | | -+=============+=============+=============+=============+==================+ -| Right user | demo | ${EMPTY} | 1 | This is a test | -| empty pass | | | | case | -| | | | | documentation of | -| | | | | the first one. | -+-------------+-------------+-------------+-------------+------------------+ -| Right user | demo | FooBar | 2,3,foo | This test | -| wrong pass | | | | case has | -| | | | | the Tags | -| | | | | 2,3 and foo | -| | | | | assigned. | -+-------------+-------------+-------------+-------------+------------------+ -| | ${EMPTY} | mode | 1,2,3,4 | This test | -| | | | | case has a | -| | | | | generated | -| | | | | name based | -| | | | | on template | -| | | | | name. | -+-------------+-------------+-------------+-------------+------------------+ -| | ${EMPTY} | ${EMPTY} | | | -+-------------+-------------+-------------+-------------+------------------+ -| | ${EMPTY} | FooBar | | | -+-------------+-------------+-------------+-------------+------------------+ -| | FooBar | mode | | | -+-------------+-------------+-------------+-------------+------------------+ -| | FooBar | ${EMPTY} | | | -+-------------+-------------+-------------+-------------+------------------+ -| | FooBar | FooBar | | | -+-------------+-------------+-------------+-------------+------------------+ - -In this data file, eight test cases are defined. Each line specifies one -test case. The first two test cases have specific names. The other six -test cases will generate names based on template test cases name with -the replacement of variables in this name. The order of columns is -irrelevant except the first column, ``*** Test Cases ***`` - -Supported Data Types -~~~~~~~~~~~~~~~~~~~~ - -In general DataDriver supports any Object that is handed over from the DataReader. -However the text based readers for csv, excel and so do support different types as well. -DataDriver supports Robot Framework® Scalar variables as well as Dictionaries and Lists. -It also support python literal evaluations. - -Scalar Variables -^^^^^^^^^^^^^^^^ - -The Prefix ``$`` defines that the value in the cell is taken as in Robot Framework® Syntax. -``String`` is ``str``, ``${1}`` is ``int`` and ``${None}`` is NoneType. -The Prefix only defines the value typ. It can also be used to assign a scalar to a dictionary key. -See example table: ``${user}[id]`` - - -Dictionary Variables -^^^^^^^^^^^^^^^^^^^^ + *** Settings *** + Library DataDriver .xlsx -Dictionaries can be created in different ways. + or: -One option is, to use the prefix ``&``. -If a variable is defined that was (i.e. ``&{dict}``) the cell value is interpreted the same way, -the BuiltIn keyword `Create Dictionary `_ would do. -The arguments here are comma (``,``) separated. -See example table: ``&{dict}`` + .. code :: robotframework -The other option is to define scalar variables in dictionary syntax like ``${user}[name]`` or ``${user.name}`` -That can be also nested dictionaries. DataDriver will create Robot Framework® (DotDict) Dictionaries, that can be accessed with ``${user.name.first}`` -See example table: ``${user}[name][first]`` - - -List Variables -^^^^^^^^^^^^^^ - -Lists can be created with the prefix ``@`` as comma (``,``) separated list. -See example table: ``@{list}`` - -Be aware that a list with an empty string has to be the cell content `${Empty}`. - -Python Literals -^^^^^^^^^^^^^^^ - -DataDriver can evaluate Literals. -It uses the prefix ``e`` for that. (i.e. ``e{list_eval}``) -For that it uses `BuiltIn Evaluate `_ - -See example table: ``e{user.chk}`` - - -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``*** Test Cases ***`` | ``${scalar}`` | ``@{list}`` | ``e{list_eval}`` | ``&{dict}`` | ``e{dict_eval}`` | ``e{eval}`` | ``${exp_eval}`` | ``${user}[id]`` | ``${user}[name][first]`` | ``${user.name.last}`` | ``e{user.chk}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``One`` | ``Sum List`` | ``1,2,3,4`` | ``["1","2","3","4"]`` | ``key=value`` | ``{'key': 'value'}`` | ``[1,2,3,4]`` | ``10`` | ``1`` | ``Pekka`` | ``Klärck`` | ``{'id': '1', 'name': {'first': 'Pekka', 'last': 'Klärck'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``Two`` | ``Should be Equal`` | ``a,b,c,d`` | ``["a","b","c","d"]`` | ``key,value`` | ``{'key': 'value'}`` | ``True`` | ``${true}`` | ``2`` | ``Ed`` | ``Manlove`` | ``{'id': '2', 'name': {'first': 'Ed', 'last': 'Manlove'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``Three`` | ``Whos your Daddy`` | ``!,",',$`` | ``["!",'"',"'","$"]`` | ``z,value,a,value2`` | ``{'a': 'value2', 'z': 'value'}`` | ``{'Daddy' : 'René'}`` | ``René`` | ``3`` | ``Tatu`` | ``Aalto`` | ``{'id': '3', 'name': {'first': 'Tatu', 'last': 'Aalto'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``4`` | ``Should be Equal`` | ``1`` | ``["1"]`` | ``key=value`` | ``{'key': 'value'}`` | ``1`` | ``${1}`` | ``4`` | ``Jani`` | ``Mikkonen`` | ``{'id': '4', 'name': {'first': 'Jani', 'last': 'Mikkonen'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``5`` | ``Should be Equal`` | | ``[]`` | ``a=${2}`` | ``{'a':2}`` | ``"string"`` | ``string`` | ``5`` | ``Mikko`` | ``Korpela`` | ``{'id': '5', 'name': {'first': 'Mikko', 'last': 'Korpela'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ -| ``6`` | ``Should be Equal`` | ``[1,2]`` | ``["[1","2]"]`` | ``key=value,key2=value2`` | ``{'key': 'value', 'key2': 'value2'}`` | ``None`` | ``${none}`` | ``6`` | ``Ismo`` | ``Aro`` | ``{'id': '6', 'name': {'first': 'Ismo', 'last': 'Aro'}}`` | -+--------------------------+-----------------------+---------------+-------------------------+-----------------------------+------------------------------------------+--------------------------+-------------------+-------------------+----------------------------+-------------------------+------------------------------------------------------------------+ - - -Accessing Test Data From Robot Variables ----------------------------------------- - -If neccesary it is possible to access the fetched data tables directly from a Robot Framework® variable. -This could be helpfull in Test Setup or in Suite Setup. - -There are three variables available within the Data-Driven Suite: - -@{DataDriver_DATA_LIST} -~~~~~~~~~~~~~~~~~~~~~~~ - -A list as suite variable containing a robot dictionary for each test case that is selected for execution. - -.. code :: json - - [ - { - "test_case_name": "Right user empty pass", - "arguments": { - "${username}": "demo", - "${password}": "${EMPTY}" - }, - "tags": [ - "1" - ], - "documentation": "This is a test case documentation of the first one." - }, - { - "test_case_name": "Right user wrong pass", - "arguments": { - "${username}": "demo", - "${password}": "FooBar" - }, - "tags": [ - "2", - "3", - "foo" - ], - "documentation": "This test case has the Tags 2,3 and foo" - }, - { - "test_case_name": "Login with user '${EMPTY}' and password 'mode'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "mode" - }, - "tags": [ - "1", - "2", - "3", - "4" - ], - "documentation": "This test case has a generated name based on template name." - }, - { - "test_case_name": "Login with user '${EMPTY}' and password '${EMPTY}'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "${EMPTY}" - }, - "tags": [ - "" - ], - "documentation": "" - }, - { - "test_case_name": "Login with user '${EMPTY}' and password 'FooBar'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "FooBar" - }, - "tags": [ - "" - ], - "documentation": "" - }, - { - "test_case_name": "Login with user 'FooBar' and password 'mode'", - "arguments": { - "${username}": "FooBar", - "${password}": "mode" - }, - "tags": [ - "foo", - "1" - ], - "documentation": "" - }, - { - "test_case_name": "Login with user 'FooBar' and password '${EMPTY}'", - "arguments": { - "${username}": "FooBar", - "${password}": "${EMPTY}" - }, - "tags": [ - "foo" - ], - "documentation": "" - }, - { - "test_case_name": "Login with user 'FooBar' and password 'FooBar'", - "arguments": { - "${username}": "FooBar", - "${password}": "FooBar" - }, - "tags": [ - "foo", - "2" - ], - "documentation": "" - } - ] - -This can be accessed as usual in Robot Framework®. - -``${DataDriver_DATA_LIST}[2][arguments][\${password}]`` would result in ``mode`` . - - - -&{DataDriver_DATA_DICT} -~~~~~~~~~~~~~~~~~~~~~~~ - -A dictionary as suite variable that contains the same data as the list, with the test names as keys. - -.. code :: json - - { - "Right user empty pass": { - "test_case_name": "Right user empty pass", - "arguments": { - "${username}": "demo", - "${password}": "${EMPTY}" - }, - "tags": [ - "1" - ], - "documentation": "This is a test case documentation of the first one." - }, - "Right user wrong pass": { - "test_case_name": "Right user wrong pass", - "arguments": { - "${username}": "demo", - "${password}": "FooBar" - }, - "tags": [ - "2", - "3", - "foo" - ], - "documentation": "This test case has the Tags 2,3 and foo" - }, - "Login with user '${EMPTY}' and password 'mode'": { - "test_case_name": "Login with user '${EMPTY}' and password 'mode'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "mode" - }, - "tags": [ - "1", - "2", - "3", - "4" - ], - "documentation": "This test case has a generated name based on template name." - }, - "Login with user '${EMPTY}' and password '${EMPTY}'": { - "test_case_name": "Login with user '${EMPTY}' and password '${EMPTY}'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "${EMPTY}" - }, - "tags": [ - "" - ], - "documentation": "" - }, - "Login with user '${EMPTY}' and password 'FooBar'": { - "test_case_name": "Login with user '${EMPTY}' and password 'FooBar'", - "arguments": { - "${username}": "${EMPTY}", - "${password}": "FooBar" - }, - "tags": [ - "" - ], - "documentation": "" - }, - "Login with user 'FooBar' and password 'mode'": { - "test_case_name": "Login with user 'FooBar' and password 'mode'", - "arguments": { - "${username}": "FooBar", - "${password}": "mode" - }, - "tags": [ - "foo", - "1" - ], - "documentation": "" - }, - "Login with user 'FooBar' and password '${EMPTY}'": { - "test_case_name": "Login with user 'FooBar' and password '${EMPTY}'", - "arguments": { - "${username}": "FooBar", - "${password}": "${EMPTY}" - }, - "tags": [ - "foo" - ], - "documentation": "" - }, - "Login with user 'FooBar' and password 'FooBar'": { - "test_case_name": "Login with user 'FooBar' and password 'FooBar'", - "arguments": { - "${username}": "FooBar", - "${password}": "FooBar" - }, - "tags": [ - "foo", - "2" - ], - "documentation": "" - } - } - -&{DataDriver_TEST_DATA} -~~~~~~~~~~~~~~~~~~~~~~~ - -A dictionary as test variable that contains the test data of the current test case. -This dictionary does also contain arguments that are not used in the ``Test Template`` keyword. -This can be used in Test Setup and within a test case. - -.. code :: json - - { - "test_case_name": "Right user wrong pass", - "arguments": { - "${username}": "demo", - "${password}": "FooBar" - }, - "tags": [ - "2", - "3", - "foo" - ], - "documentation": "This test case has the Tags 2,3 and foo" - } - - -Data Sources ------------- - - -CSV / TSV (Character-separated values) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -By default DataDriver reads csv files. With the `Encoding and CSV -Dialect <#file-encoding-and-csv-dialect>`__ settings you may configure which -structure your data source has. - - -XLS / XLSX Files -~~~~~~~~~~~~~~~~ - -To use Excel file types, you have to install DataDriver with the Extra XLS. - -If you want to use Excel based data sources, you may just set the file -to the extention or you may point to the correct file. If the extention -is ".xls" or ".xlsx" DataDriver will interpret it as Excel file. -You may select the sheet which will be read by the option ``sheet_name``. -By default it is set to 0 which will be the first table sheet. -You may use sheet index (0 is first sheet) or sheet name(case sensitive). -XLS interpreter will ignore all other options like encoding, delimiters etc. - -.. code :: robotframework - - *** Settings *** - Library DataDriver .xlsx + *** Settings *** + Library DataDriver file=my_data_source.xlsx sheet_name=2nd Sheet -or: -.. code :: robotframework + MS Excel and typed cells + ^^^^^^^^^^^^^^^^^^^^^^^^ - *** Settings *** - Library DataDriver file=my_data_source.xlsx sheet_name=2nd Sheet + Microsoft Excel xls or xlsx file have the possibility to type thair data + cells. Numbers are typically of the type float. If these data are not + explicitly defined as text in Excel, pandas will read it as the type + that is has in excel. Because we have to work with strings in Robot + Framework® these data are converted to string. This leads to the + situation that a European time value like "04.02.2019" (4th January + 2019) is handed over to Robot Framework® in Iso time "2019-01-04 + 00:00:00". This may cause unwanted behavior. To mitigate this risk you + should define Excel based files explicitly as text within Excel. + Alternatively you may deactivate that string conversion. + To do so, you have to add the option ``preserve_xls_types`` to ``True``. + In that case, you will get str, float, boolean, int, datetime.time, + datetime.datetime and some others. -MS Excel and typed cells -^^^^^^^^^^^^^^^^^^^^^^^^ + .. code :: robotframework -Microsoft Excel xls or xlsx file have the possibility to type thair data -cells. Numbers are typically of the type float. If these data are not -explicitly defined as text in Excel, pandas will read it as the type -that is has in excel. Because we have to work with strings in Robot -Framework® these data are converted to string. This leads to the -situation that a European time value like "04.02.2019" (4th January -2019) is handed over to Robot Framework® in Iso time "2019-01-04 -00:00:00". This may cause unwanted behavior. To mitigate this risk you -should define Excel based files explicitly as text within Excel. + *** Settings *** + Library DataDriver file=my_data_source.xlsx preserve_xls_types=True -Alternatively you may deactivate that string conversion. -To do so, you have to add the option ``preserve_xls_types`` to ``True``. -In that case, you will get str, float, boolean, int, datetime.time, -datetime.datetime and some others. + PICT (Pairwise Independent Combinatorial Testing) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code :: robotframework + Pict is able to generate data files based on a model file. + https://github.com/Microsoft/pict - *** Settings *** - Library DataDriver file=my_data_source.xlsx preserve_xls_types=True + Documentation: https://github.com/Microsoft/pict/blob/master/doc/pict.md -PICT (Pairwise Independent Combinatorial Testing) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pict is able to generate data files based on a model file. -https://github.com/Microsoft/pict + Requirements + ^^^^^^^^^^^^ -Documentation: https://github.com/Microsoft/pict/blob/master/doc/pict.md + - Path to pict.exe must be set in the %PATH% environment variable. + - Data model file has the file extention ".pict" + - Pict model file must be encoded in UTF-8 -Requirements -^^^^^^^^^^^^ + How it works + ^^^^^^^^^^^^ -- Path to pict.exe must be set in the %PATH% environment variable. -- Data model file has the file extention ".pict" -- Pict model file must be encoded in UTF-8 + If the file option is set to a file with the extention pict, DataDriver + will hand over this file to pict.exe and let it automatically generates + a file with the extention ".pictout". This file will the be used as data + source for the test generation. (It is tab seperated and UTF-8 encoded) + Except the file option all other options of the library will be ignored. + .. code :: robotframework -How it works -^^^^^^^^^^^^ + *** Settings *** + Library DataDriver my_model_file.pict -If the file option is set to a file with the extention pict, DataDriver -will hand over this file to pict.exe and let it automatically generates -a file with the extention ".pictout". This file will the be used as data -source for the test generation. (It is tab seperated and UTF-8 encoded) -Except the file option all other options of the library will be ignored. -.. code :: robotframework + Glob File Pattern + ~~~~~~~~~~~~~~~~~ - *** Settings *** - Library DataDriver my_model_file.pict + This module implements a reader class that creates a test case for each file or folder that matches the given glob pattern. + With an optional argument "arg_name" you can modify the argument that will be set. See folder example. -Glob File Pattern -~~~~~~~~~~~~~~~~~ + Example with json files: -This module implements a reader class that creates a test case for each file or folder that matches the given glob pattern. + .. code :: robotframework -With an optional argument "arg_name" you can modify the argument that will be set. See folder example. + *** Settings *** + Library DataDriver file=${CURDIR}/DataFiles/*_File.json reader_class=glob_reader + Library OperatingSystem + Test Template Test all Files -Example with json files: -.. code :: robotframework + *** Test Cases *** + Glob_Reader_Test Wrong_File.NoJson - *** Settings *** - Library DataDriver file=${CURDIR}/DataFiles/*_File.json reader_class=glob_reader - Library OperatingSystem - Test Template Test all Files + *** Keywords *** + Test all Files + [Arguments] ${file_name} + ${file_content}= Get File ${file_name} + ${content}= Evaluate json.loads($file_content)["test_case"] + Should Be Equal ${TEST_NAME} ${content} - *** Test Cases *** - Glob_Reader_Test Wrong_File.NoJson + Example with folders: - *** Keywords *** - Test all Files - [Arguments] ${file_name} - ${file_content}= Get File ${file_name} - ${content}= Evaluate json.loads($file_content)["test_case"] - Should Be Equal ${TEST_NAME} ${content} + .. code :: robotframework + *** Settings *** + Library DataDriver file=${CURDIR}/FoldersToFind/*/ reader_class=glob_reader arg_name=\${folder_name} + Library OperatingSystem + Test Template Test all Files -Example with folders: -.. code :: robotframework + *** Test Cases *** + Glob_Reader_Test Wrong_File.NoJson - *** Settings *** - Library DataDriver file=${CURDIR}/FoldersToFind/*/ reader_class=glob_reader arg_name=\${folder_name} - Library OperatingSystem - Test Template Test all Files + *** Keywords *** + Test all Files + [Arguments] ${folder_name} + ${content}= Get File ${folder_name}/verify.txt + Should Be Equal ${TEST_NAME} ${content} - *** Test Cases *** - Glob_Reader_Test Wrong_File.NoJson + File Encoding and CSV Dialect + ----------------------------- - *** Keywords *** - Test all Files - [Arguments] ${folder_name} - ${content}= Get File ${folder_name}/verify.txt - Should Be Equal ${TEST_NAME} ${content} + CSV is far away from well designed and has absolutely no "common" + format. Therefore it is possible to define your own dialect or use + predefined. The default is Excel-EU which is a semicolon separated + file. + These Settings are changeable as options of the Data Driver Library. -File Encoding and CSV Dialect ------------------------------ + file= + ~~~~~ -CSV is far away from well designed and has absolutely no "common" -format. Therefore it is possible to define your own dialect or use -predefined. The default is Excel-EU which is a semicolon separated -file. -These Settings are changeable as options of the Data Driver Library. + .. code :: robotframework + *** Settings *** + Library DataDriver file=../data/my_data_source.csv -file= -~~~~~ -.. code :: robotframework + - None(default): Data Driver will search in the test suites folder if a + \*.csv file with the same name than the test suite \*.robot file exists + - only file extention: if you just set a file extentions like ".xls" or + ".xlsx" DataDriver will search + - absolute path: If an absolute path to a file is set, DataDriver tries + to find and open the given data file. + - relative path: If the option does not point to a data file as an + absolute path, Data Driver tries to find a data file relative to the + folder where the test suite is located. - *** Settings *** - Library DataDriver file=../data/my_data_source.csv + encoding= + ~~~~~~~~~ -- None(default): Data Driver will search in the test suites folder if a - \*.csv file with the same name than the test suite \*.robot file exists -- only file extention: if you just set a file extentions like ".xls" or - ".xlsx" DataDriver will search -- absolute path: If an absolute path to a file is set, DataDriver tries - to find and open the given data file. -- relative path: If the option does not point to a data file as an - absolute path, Data Driver tries to find a data file relative to the - folder where the test suite is located. + ``encoding=`` must be set if it shall not be cp1252. + **Examples**: -encoding= -~~~~~~~~~ + ``cp1252, ascii, iso-8859-1, latin-1, utf_8, utf_16, utf_16_be, utf_16_le`` -``encoding=`` must be set if it shall not be cp1252. + **cp1252** is: -**Examples**: + - Code Page 1252 + - Windows-1252 + - Windows Western European -``cp1252, ascii, iso-8859-1, latin-1, utf_8, utf_16, utf_16_be, utf_16_le`` + Most characters are same between ISO-8859-1 (Latin-1) except for the code points 128-159 (0x80-0x9F). + These Characters are available in cp1252 which are not present in Latin-1. -**cp1252** is: + ``€ ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ Ž ‘ ’ “ ” • – — ˜ ™ š › œ ž Ÿ`` -- Code Page 1252 -- Windows-1252 -- Windows Western European + See `Python Standard Encoding `_ for more encodings -Most characters are same between ISO-8859-1 (Latin-1) except for the code points 128-159 (0x80-0x9F). -These Characters are available in cp1252 which are not present in Latin-1. -``€ ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ Ž ‘ ’ “ ” • – — ˜ ™ š › œ ž Ÿ`` + dialect= + ~~~~~~~~ -See `Python Standard Encoding `_ for more encodings + You may change the CSV Dialect here. + The dialect option can be one of the following: + - Excel-EU + - excel + - excel-tab + - unix + - UserDefined + supported Dialects are: -dialect= -~~~~~~~~ + .. code:: python -You may change the CSV Dialect here. -The dialect option can be one of the following: -- Excel-EU -- excel -- excel-tab -- unix -- UserDefined + "Excel-EU" + delimiter=';', + quotechar='"', + escapechar='\\', + doublequote=True, + skipinitialspace=False, + lineterminator="\\r\\n", + quoting=csv.QUOTE_ALL -supported Dialects are: + "excel" + delimiter = ',' + quotechar = '"' + doublequote = True + skipinitialspace = False + lineterminator = '\\r\\n' + quoting = QUOTE_MINIMAL -.. code:: python + "excel-tab" + delimiter = '\\t' + quotechar = '"' + doublequote = True + skipinitialspace = False + lineterminator = '\\r\\n' + quoting = QUOTE_MINIMAL - "Excel-EU" - delimiter=';', - quotechar='"', - escapechar='\\', - doublequote=True, - skipinitialspace=False, - lineterminator="\\r\\n", - quoting=csv.QUOTE_ALL + "unix" + delimiter = ',' + quotechar = '"' + doublequote = True + skipinitialspace = False + lineterminator = '\\n' + quoting = QUOTE_ALL - "excel" - delimiter = ',' - quotechar = '"' - doublequote = True - skipinitialspace = False - lineterminator = '\\r\\n' - quoting = QUOTE_MINIMAL - "excel-tab" - delimiter = '\\t' - quotechar = '"' - doublequote = True - skipinitialspace = False - lineterminator = '\\r\\n' - quoting = QUOTE_MINIMAL - "unix" - delimiter = ',' - quotechar = '"' - doublequote = True - skipinitialspace = False - lineterminator = '\\n' - quoting = QUOTE_ALL + Usage in Robot Framework® + .. code :: robotframework + *** Settings *** + Library DataDriver my_data_file.csv dialect=excel -Usage in Robot Framework® -.. code :: robotframework - *** Settings *** - Library DataDriver my_data_file.csv dialect=excel + .. code :: robotframework + *** Settings *** + Library DataDriver my_data_file.csv dialect=excel_tab -.. code :: robotframework - *** Settings *** - Library DataDriver my_data_file.csv dialect=excel_tab + .. code :: robotframework + *** Settings *** + Library DataDriver my_data_file.csv dialect=unix_dialect -.. code :: robotframework - *** Settings *** - Library DataDriver my_data_file.csv dialect=unix_dialect + Example User Defined + ^^^^^^^^^^^^^^^^^^^^ + User may define the format completely free. + If an option is not set, the default values are used. + To register a userdefined format user have to set the + option ``dialect`` to ``UserDefined`` -Example User Defined -^^^^^^^^^^^^^^^^^^^^ + Usage in Robot Framework® -User may define the format completely free. -If an option is not set, the default values are used. -To register a userdefined format user have to set the -option ``dialect`` to ``UserDefined`` + .. code :: robotframework + *** Settings *** + Library DataDriver my_data_file.csv + ... dialect=UserDefined + ... delimiter=. + ... lineterminator=\\n -Usage in Robot Framework® -.. code :: robotframework - *** Settings *** - Library DataDriver my_data_file.csv - ... dialect=UserDefined - ... delimiter=. - ... lineterminator=\\n + Defaults: + ~~~~~~~~~ + .. code:: python + file=None, + encoding='cp1252', + dialect='Excel-EU', + delimiter=';', + quotechar='"', + escapechar='\\\\', + doublequote=True, + skipinitialspace=False, + lineterminator='\\r\\n', + sheet_name=0 -Defaults: -~~~~~~~~~ -.. code:: python + Custom DataReader Classes + ------------------------- - file=None, - encoding='cp1252', - dialect='Excel-EU', - delimiter=';', - quotechar='"', - escapechar='\\\\', - doublequote=True, - skipinitialspace=False, - lineterminator='\\r\\n', - sheet_name=0 + It is possible to write your own DataReader Class as a plugin for DataDriver. + DataReader Classes are called from DataDriver to return a list of TestCaseData. -Custom DataReader Classes -------------------------- + Using Custom DataReader + ~~~~~~~~~~~~~~~~~~~~~~~ -It is possible to write your own DataReader Class as a plugin for DataDriver. -DataReader Classes are called from DataDriver to return a list of TestCaseData. + DataReader classes are loaded dynamically into DataDriver while runtime. + DataDriver identifies the DataReader to load by the file extantion of the data file or by the option ``reader_class``. -Using Custom DataReader -~~~~~~~~~~~~~~~~~~~~~~~ + Select Reader by File Extension: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -DataReader classes are loaded dynamically into DataDriver while runtime. -DataDriver identifies the DataReader to load by the file extantion of the data file or by the option ``reader_class``. + .. code :: robotframework + *** Settings *** + Library DataDriver file=mydata.csv -Select Reader by File Extension: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + This will load the class ``csv_reader`` from ``csv_reader.py`` from the same folder. -.. code :: robotframework - *** Settings *** - Library DataDriver file=mydata.csv + Select Reader by Option: + ^^^^^^^^^^^^^^^^^^^^^^^^ -This will load the class ``csv_reader`` from ``csv_reader.py`` from the same folder. + .. code :: robotframework + *** Settings *** + Library DataDriver file=mydata.csv reader_class=generic_csv_reader dialect=userdefined delimiter=\\t encoding=UTF-8 -Select Reader by Option: -^^^^^^^^^^^^^^^^^^^^^^^^ + This will load the class ``generic_csv_reader`` from ``generic_csv_reader.py`` from same folder. -.. code :: robotframework - *** Settings *** - Library DataDriver file=mydata.csv reader_class=generic_csv_reader dialect=userdefined delimiter=\\t encoding=UTF-8 + Create Custom Reader + ~~~~~~~~~~~~~~~~~~~~ -This will load the class ``generic_csv_reader`` from ``generic_csv_reader.py`` from same folder. + Recommendation: + Have a look to the Source Code of existing DataReader like ``csv_reader.py`` or ``generic_csv_reader.py`` . -Create Custom Reader -~~~~~~~~~~~~~~~~~~~~ + To write your own reader, create a class inherited from ``AbstractReaderClass``. -Recommendation: + Your class will get all available configs from DataDriver as an object of ``ReaderConfig`` on ``__init__``. -Have a look to the Source Code of existing DataReader like ``csv_reader.py`` or ``generic_csv_reader.py`` . + DataDriver will call the method ``get_data_from_source`` + This method should then load your data from your custom source and stores them into list of object of ``TestCaseData``. + This List of ``TestCaseData`` will be returned to DataDriver. -To write your own reader, create a class inherited from ``AbstractReaderClass``. + ``AbstractReaderClass`` has also some optional helper methods that may be useful. -Your class will get all available configs from DataDriver as an object of ``ReaderConfig`` on ``__init__``. + You can either place the custom reader with the others in DataDriver folder or anywhere on the disk. + In the first case or if your custom reader is in python path just use it like the others by name: -DataDriver will call the method ``get_data_from_source`` -This method should then load your data from your custom source and stores them into list of object of ``TestCaseData``. -This List of ``TestCaseData`` will be returned to DataDriver. + .. code :: robotframework -``AbstractReaderClass`` has also some optional helper methods that may be useful. + *** Settings *** + Library DataDriver reader_class=my_reader -You can either place the custom reader with the others in DataDriver folder or anywhere on the disk. -In the first case or if your custom reader is in python path just use it like the others by name: + In case it is somewhere on the disk, it is possible to use an absolute or relative path to a custom Reader. + Imports of custom readers follow the same rules like importing Robot Framework® libraries. + Path can be relative to ${EXECDIR} or to DataDriver/__init__.py: -.. code :: robotframework - *** Settings *** - Library DataDriver reader_class=my_reader + .. code :: robotframework -In case it is somewhere on the disk, it is possible to use an absolute or relative path to a custom Reader. -Imports of custom readers follow the same rules like importing Robot Framework® libraries. -Path can be relative to ${EXECDIR} or to DataDriver/__init__.py: + *** Settings *** + Library DataDriver reader_class=C:/data/my_reader.py # set custom reader + ... file_search_strategy=None # set DataDriver to not check file + ... min=0 # kwargs arguments for custom reader + ... max=62 + This `my_reader.py` should implement a class inherited from AbstractReaderClass that is named `my_reader`. -.. code :: robotframework + .. code :: python - *** Settings *** - Library DataDriver reader_class=C:/data/my_reader.py # set custom reader - ... file_search_strategy=None # set DataDriver to not check file - ... min=0 # kwargs arguments for custom reader - ... max=62 + from DataDriver.AbstractReaderClass import AbstractReaderClass # inherit class from AbstractReaderClass + from DataDriver.ReaderConfig import TestCaseData # return list of TestCaseData to DataDriver -This `my_reader.py` should implement a class inherited from AbstractReaderClass that is named `my_reader`. -.. code :: python + class my_reader(AbstractReaderClass): - from DataDriver.AbstractReaderClass import AbstractReaderClass # inherit class from AbstractReaderClass - from DataDriver.ReaderConfig import TestCaseData # return list of TestCaseData to DataDriver + def get_data_from_source(self): # This method will be called from DataDriver to get the TestCaseData list. + test_data = [] + for i in range(int(self.kwargs['min']), int(self.kwargs['max'])): # Dummy code to just generate some data + args = {'${var_1}': str(i), '${var_2}': str(i)} # args is a dictionary. Variable name is the key, value is value. + test_data.append(TestCaseData(f'test {i}', args, ['tag'])) # add a TestCaseData object to the list of tests. + return test_data # return the list of TestCaseData to DataDriver - class my_reader(AbstractReaderClass): + See other readers as example. - def get_data_from_source(self): # This method will be called from DataDriver to get the TestCaseData list. - test_data = [] - for i in range(int(self.kwargs['min']), int(self.kwargs['max'])): # Dummy code to just generate some data - args = {'${var_1}': str(i), '${var_2}': str(i)} # args is a dictionary. Variable name is the key, value is value. - test_data.append(TestCaseData(f'test {i}', args, ['tag'])) # add a TestCaseData object to the list of tests. - return test_data # return the list of TestCaseData to DataDriver + Selection of Test Cases to Execute + ---------------------------------- -See other readers as example. + Because test cases that are created by DataDriver after parsing while execution, + it is not possible to use some Robot Framework® methods to select test cases. -Selection of Test Cases to Execute ----------------------------------- + Examples for options that have to be used differently: -Because test cases that are created by DataDriver after parsing while execution, -it is not possible to use some Robot Framework® methods to select test cases. + +-------------------+-----------------------------------------------------------------------+ + | robot option | Description | + +===================+=======================================================================+ + | ``--test`` | Selects the test cases by name. | + +-------------------+-----------------------------------------------------------------------+ + | ``--task`` | Alias for --test that can be used when executing tasks. | + +-------------------+-----------------------------------------------------------------------+ + | ``--rerunfailed`` | Selects failed tests from an earlier output file to be re-executed. | + +-------------------+-----------------------------------------------------------------------+ + | ``--include`` | Selects the test cases by tag. | + +-------------------+-----------------------------------------------------------------------+ + | ``--exclude`` | Selects the test cases by tag. | + +-------------------+-----------------------------------------------------------------------+ -Examples for options that have to be used differently: + Selection of test cases by name + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+-------------------+-----------------------------------------------------------------------+ -| robot option | Description | -+===================+=======================================================================+ -| ``--test`` | Selects the test cases by name. | -+-------------------+-----------------------------------------------------------------------+ -| ``--task`` | Alias for --test that can be used when executing tasks. | -+-------------------+-----------------------------------------------------------------------+ -| ``--rerunfailed`` | Selects failed tests from an earlier output file to be re-executed. | -+-------------------+-----------------------------------------------------------------------+ -| ``--include`` | Selects the test cases by tag. | -+-------------------+-----------------------------------------------------------------------+ -| ``--exclude`` | Selects the test cases by tag. | -+-------------------+-----------------------------------------------------------------------+ + Select a single test case: + ^^^^^^^^^^^^^^^^^^^^^^^^^^ -Selection of test cases by name -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + To execute just a single test case by its exact name it is possible to execute the test suite + and set the global variable ${DYNAMICTEST} with the name of the test case to execute as value. + Pattern must be ``suitename.testcasename``. + Example: -Select a single test case: -^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. code :: -To execute just a single test case by its exact name it is possible to execute the test suite -and set the global variable ${DYNAMICTEST} with the name of the test case to execute as value. -Pattern must be ``suitename.testcasename``. + robot --variable "DYNAMICTEST:my suite name.test case to be executed" my_suite_name.robot -Example: + Pabot uses this feature to execute a single test case when using ``--testlevelsplit`` -.. code :: - robot --variable "DYNAMICTEST:my suite name.test case to be executed" my_suite_name.robot + Select a list of test cases: + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Pabot uses this feature to execute a single test case when using ``--testlevelsplit`` + It is possible to set a list of test case names by using the variable ${DYNAMICTESTS} (plural). + This variable must be a string and the list of names must be pipe-seperated (``|``). + Example: -Select a list of test cases: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. code:: -It is possible to set a list of test case names by using the variable ${DYNAMICTESTS} (plural). -This variable must be a string and the list of names must be pipe-seperated (``|``). + robot --variable DYNAMICTESTS:firstsuitename.testcase1|firstsuitename.testcase3|anothersuitename.othertestcase foldername -Example: + It is also possible to set the variable @{DYNAMICTESTS} as a list variable from i.e. python code. -.. code:: - robot --variable DYNAMICTESTS:firstsuitename.testcase1|firstsuitename.testcase3|anothersuitename.othertestcase foldername + Re-run failed test cases: + ~~~~~~~~~~~~~~~~~~~~~~~~~ -It is also possible to set the variable @{DYNAMICTESTS} as a list variable from i.e. python code. + Because it is not possible to use the command line argument ``--rerunfailed`` from robot directly, + DataDriver brings a Pre-Run-Modifier that handles this issue. + Normally reexecution of failed testcases has three steps. -Re-run failed test cases: -~~~~~~~~~~~~~~~~~~~~~~~~~ + - original execution + - re-execution the failed ones based on original execution output + - merging original execution output with re-execution output -Because it is not possible to use the command line argument ``--rerunfailed`` from robot directly, -DataDriver brings a Pre-Run-Modifier that handles this issue. + The DataDriver.rerunfailed Pre-Run-Modifier removes all passed test cases based on a former output.xml. -Normally reexecution of failed testcases has three steps. + Example: -- original execution -- re-execution the failed ones based on original execution output -- merging original execution output with re-execution output + .. code :: -The DataDriver.rerunfailed Pre-Run-Modifier removes all passed test cases based on a former output.xml. + robot --output original.xml tests # first execute all tests + robot --prerunmodifier DataDriver.rerunfailed:original.xml --output rerun.xml tests # then re-execute failing + rebot --merge original.xml rerun.xml # finally merge results -Example: -.. code :: + Be aware, that in this case it is not allowed to use "``:``" as character in the original output file path. + If you want to set a full path on windows like ``e:\\myrobottest\\output.xml`` you have to use "``;``" + as argument seperator. - robot --output original.xml tests # first execute all tests - robot --prerunmodifier DataDriver.rerunfailed:original.xml --output rerun.xml tests # then re-execute failing - rebot --merge original.xml rerun.xml # finally merge results + Example: + .. code :: -Be aware, that in this case it is not allowed to use "``:``" as character in the original output file path. -If you want to set a full path on windows like ``e:\\myrobottest\\output.xml`` you have to use "``;``" -as argument seperator. + robot --prerunmodifier DataDriver.rerunfailed;e:\\myrobottest\\output.xml --output e:\\myrobottest\\rerun.xml tests -Example: -.. code :: - robot --prerunmodifier DataDriver.rerunfailed;e:\\myrobottest\\output.xml --output e:\\myrobottest\\rerun.xml tests + Filtering with tags. + ~~~~~~~~~~~~~~~~~~~~ + New in ``0.3.1`` + It is possible to use tags to filter the data source. + To use this, tags must be assigned to the test cases in data source. -Filtering with tags. -~~~~~~~~~~~~~~~~~~~~ -New in ``0.3.1`` + Robot Framework® Command Line Arguments + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -It is possible to use tags to filter the data source. -To use this, tags must be assigned to the test cases in data source. + To filter the source, the normal command line arguments of Robot Framework® can be used. + See Robot Framework® Userguide_ for more information + Be aware that the filtering of Robot Framework® itself is done before DataDriver is called. + This means if the Template test is already filtered out by Robot Framework®, DataDriver can never be called. + If you want to use ``--include`` the DataDriver TestSuite should have a ``DefaultTag`` or ``ForceTag`` that + fulfills these requirements. + .. _Userguide: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns -Robot Framework® Command Line Arguments -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + Example: ``robot --include 1OR2 --exclude foo DataDriven.robot`` -To filter the source, the normal command line arguments of Robot Framework® can be used. -See Robot Framework® Userguide_ for more information -Be aware that the filtering of Robot Framework® itself is done before DataDriver is called. -This means if the Template test is already filtered out by Robot Framework®, DataDriver can never be called. -If you want to use ``--include`` the DataDriver TestSuite should have a ``DefaultTag`` or ``ForceTag`` that -fulfills these requirements. -.. _Userguide: http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns + Filter based on Library Options + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Example: ``robot --include 1OR2 --exclude foo DataDriven.robot`` + It is also possible to filter the data source by an init option of DataDriver. + If these Options are set, Robot Framework® Filtering will be ignored. + Example: -Filter based on Library Options -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + .. code :: robotframework -It is also possible to filter the data source by an init option of DataDriver. -If these Options are set, Robot Framework® Filtering will be ignored. + *** Settings *** + Library DataDriver include=1OR2 exclude=foo -Example: -.. code :: robotframework - *** Settings *** - Library DataDriver include=1OR2 exclude=foo + Configure DataDriver by Pre-Run Keyword + --------------------------------------- + With ``config_keyword=`` it's possible to name a keyword that will be called from Data Driver before it starts the actual processing of the ``data file``. + One possible usage is if the ``data file`` itself shall be created by another keyword dynamically during the execution of the Data Driver test suite. + The ``config_keyword=`` can be used to call that keyword and return the updated arguments (e.g. ``file``) back to the Data Driver Library. + The ``config keyword`` -Configure DataDriver by Pre-Run Keyword ---------------------------------------- + - May be defined globally or inside each testsuite individually + - Gets all the arguments, that Data Driver gets from Library import, as a Robot Dictionary + - Shall return the (updated) Data Driver arguments as a Robot Dictionary -With ``config_keyword=`` it's possible to name a keyword that will be called from Data Driver before it starts the actual processing of the ``data file``. -One possible usage is if the ``data file`` itself shall be created by another keyword dynamically during the execution of the Data Driver test suite. -The ``config_keyword=`` can be used to call that keyword and return the updated arguments (e.g. ``file``) back to the Data Driver Library. + Usage in Robot Framework® -The ``config keyword`` + .. code :: robotframework -- May be defined globally or inside each testsuite individually -- Gets all the arguments, that Data Driver gets from Library import, as a Robot Dictionary -- Shall return the (updated) Data Driver arguments as a Robot Dictionary + *** Settings *** + Library OperatingSystem + Library DataDriver dialect=excel encoding=utf_8 config_keyword=Config + Test Template The Keyword -Usage in Robot Framework® + *** Test Cases *** + Test aaa -.. code :: robotframework + *** Keywords *** + The Keyword + [Arguments] ${var} + Log To Console ${var} - *** Settings *** - Library OperatingSystem - Library DataDriver dialect=excel encoding=utf_8 config_keyword=Config - Test Template The Keyword + Config + [Arguments] ${original_config} + Log To Console ${original_config.dialect} # just a log of the original + Create File ${CURDIR}/test321.csv + ... *** Test Cases ***,\${var},\\n123,111,\\n321,222, # generating file + ${new_config}= Create Dictionary file=test321.csv # set file attribute in a dictionary + [Return] ${new_config} # returns {'file': 'test321.csv'} - *** Test Cases *** - Test aaa - *** Keywords *** - The Keyword - [Arguments] ${var} - Log To Console ${var} - Config - [Arguments] ${original_config} - Log To Console ${original_config.dialect} # just a log of the original - Create File ${CURDIR}/test321.csv - ... *** Test Cases ***,\${var},\\n123,111,\\n321,222, # generating file - ${new_config}= Create Dictionary file=test321.csv # set file attribute in a dictionary - [Return] ${new_config} # returns {'file': 'test321.csv'} + Pabot and DataDriver + -------------------- + You should use Pabot version 1.10.0 or newer. + DataDriver supports ``--testlevelsplit`` from pabot only if the PabotLib is in use. + Use ``--pabotlib`` to enable that. -Pabot and DataDriver --------------------- + When using pabot like this, DataDriver automatically splits the amount of test cases into nearly same sized groups. + Is uses the processes count from pabot to calculate the groups. + When using 8 processes with 100 test cases you will get 8 groups of tests with the size of 12 to 13 tests. + These 8 groups are then executed as one block with 8 processes. + This reduces a lot of overhead with Suite Setup and Teardown. -You should use Pabot version 1.10.0 or newer. + You can switch between three modes: -DataDriver supports ``--testlevelsplit`` from pabot only if the PabotLib is in use. -Use ``--pabotlib`` to enable that. + - ``Equal``: means it creates equal sizes groups + - ``Binary``: is more complex. it created a decreasing size of containers to support better balancing. + - ``Atomic``: it does not group tests at all and runs really each test case in a separate thread. -When using pabot like this, DataDriver automatically splits the amount of test cases into nearly same sized groups. -Is uses the processes count from pabot to calculate the groups. -When using 8 processes with 100 test cases you will get 8 groups of tests with the size of 12 to 13 tests. -These 8 groups are then executed as one block with 8 processes. -This reduces a lot of overhead with Suite Setup and Teardown. + This can be set by ``optimize_pabot`` in Library import. -You can switch between three modes: -- ``Equal``: means it creates equal sizes groups -- ``Binary``: is more complex. it created a decreasing size of containers to support better balancing. -- ``Atomic``: it does not group tests at all and runs really each test case in a separate thread. + **Example**: -This can be set by ``optimize_pabot`` in Library import. + .. code :: robotframework + *** Settings *** + Library DataDriver optimize_pabot=Binary -**Example**: + Binary creates with 40 test cases and 8 threads something like that: -.. code :: robotframework + .. code :: - *** Settings *** - Library DataDriver optimize_pabot=Binary - -Binary creates with 40 test cases and 8 threads something like that: - -.. code :: - - P01: 01,02,03,04,05 - P02: 06,07,08,09,10 - P03: 11,12,13,14,15 - P04: 16,17,18,19,20 - P05: 21,22,23 - P06: 24,25,26 - P07: 27,28,29 - P08: 30,31,32 - P09: 33 - P10: 34 - P11: 35 - P12: 36 - P13: 37 - P14: 38 - P15: 39 - P16: 40 + P01: 01,02,03,04,05 + P02: 06,07,08,09,10 + P03: 11,12,13,14,15 + P04: 16,17,18,19,20 + P05: 21,22,23 + P06: 24,25,26 + P07: 27,28,29 + P08: 30,31,32 + P09: 33 + P10: 34 + P11: 35 + P12: 36 + P13: 37 + P14: 38 + P15: 39 + P16: 40 """ -# endregion + # endregion ROBOT_LIBRARY_DOC_FORMAT = "reST" ROBOT_LIBRARY_VERSION = __version__ @@ -1526,8 +1527,7 @@ def _start_suite(self, suite: TestSuite, result): self._set_date_table_to_robot_variable() debug(f"[ DataDriver ] {len(test_list)} tests added.") except Exception as e: - error(f"[ DataDriver ] Error in robot file:\n" - f' File "{suite.source}", line 0') + error(f'[ DataDriver ] Error in robot file:\n File "{suite.source}", line 0') if self.reader_config.file: error( f'In source file:\n' @@ -1603,7 +1603,10 @@ def _not_excluded_by_tags(self): def _filter_tag(self, filter_setting): tags = Tags() - if self.handle_template_tags != TagHandling.DefaultTags or len(self.test_case_data.tags) == 0: + if ( + self.handle_template_tags != TagHandling.DefaultTags + or len(self.test_case_data.tags) == 0 + ): tags.add(self.template_test.tags) tags.add(self.test_case_data.tags) return tags.match(filter_setting) @@ -1873,7 +1876,10 @@ def _get_template_arguments(self): def _add_test_case_tags(self): if isinstance(self.test_case_data.tags, list): - if self.handle_template_tags == TagHandling.DefaultTags and len(self.test_case_data.tags) > 0: + if ( + self.handle_template_tags == TagHandling.DefaultTags + and len(self.test_case_data.tags) > 0 + ): self.test.tags = Tags() for tag in self.test_case_data.tags: self.test.tags.add(tag.strip()) diff --git a/src/DataDriver/utils.py b/src/DataDriver/utils.py index 03ca79f..b4232ca 100644 --- a/src/DataDriver/utils.py +++ b/src/DataDriver/utils.py @@ -10,31 +10,32 @@ class Encodings(Enum): """ -Python comes with a number of codecs built-in, -either implemented as C functions or with dictionaries as mapping tables. -The following table lists the codecs by name, -together with a few common aliases, and the languages for which the encoding is likely used. -Neither the list of aliases nor the list of languages is meant to be exhaustive. -Notice that spelling alternatives that only differ in case or use a hyphen instead -of an underscore are also valid aliases; therefore, e.g. ``utf-8` is a valid alias for the ``utf_8`` codec. - -*CPython implementation detail:* Some common encodings can bypass the codecs lookup machinery to improve performance. -These optimization opportunities are only recognized by CPython for a limited set of (case insensitive) aliases: -utf-8, utf8, latin-1, latin1, iso-8859-1, iso8859-1, mbcs (Windows only), -ascii, us-ascii, utf-16, utf16, utf-32, utf32, and the same using underscores instead of dashes. -Using alternative aliases for these encodings may result in slower execution. - -Changed in version 3.6: Optimization opportunity recognized for us-ascii. - -Many of the character sets support the same languages. They vary in individual characters (e.g. whether the EURO SIGN is supported or not), and in the assignment of characters to code positions. For the European languages in particular, the following variants typically exist: - -- utf-8 -- cp1252 -- an ISO 8859 codeset -- a Microsoft Windows code page, which is typically derived from an 8859 codeset, but replaces control characters with additional graphic characters -- an IBM EBCDIC code page -- an IBM PC code page, which is ASCII compatible + Python comes with a number of codecs built-in, + either implemented as C functions or with dictionaries as mapping tables. + The following table lists the codecs by name, + together with a few common aliases, and the languages for which the encoding is likely used. + Neither the list of aliases nor the list of languages is meant to be exhaustive. + Notice that spelling alternatives that only differ in case or use a hyphen instead + of an underscore are also valid aliases; therefore, e.g. ``utf-8` is a valid alias for the ``utf_8`` codec. + + *CPython implementation detail:* Some common encodings can bypass the codecs lookup machinery to improve performance. + These optimization opportunities are only recognized by CPython for a limited set of (case insensitive) aliases: + utf-8, utf8, latin-1, latin1, iso-8859-1, iso8859-1, mbcs (Windows only), + ascii, us-ascii, utf-16, utf16, utf-32, utf32, and the same using underscores instead of dashes. + Using alternative aliases for these encodings may result in slower execution. + + Changed in version 3.6: Optimization opportunity recognized for us-ascii. + + Many of the character sets support the same languages. They vary in individual characters (e.g. whether the EURO SIGN is supported or not), and in the assignment of characters to code positions. For the European languages in particular, the following variants typically exist: + + - utf-8 + - cp1252 + - an ISO 8859 codeset + - a Microsoft Windows code page, which is typically derived from an 8859 codeset, but replaces control characters with additional graphic characters + - an IBM EBCDIC code page + - an IBM PC code page, which is ASCII compatible """ + ascii = auto() big5 = auto() big5hkscs = auto() @@ -136,16 +137,17 @@ class Encodings(Enum): class PabotOpt(Enum): """ -You can switch Pabot --testlevelsplit between three modes: + You can switch Pabot --testlevelsplit between three modes: -- Equal: means it creates equal sizes groups -- Binary: is more complex. it created a decreasing size of containers to support better balancing. -- Atomic: it does not group tests at all and runs really each test case in a separate thread. + - Equal: means it creates equal sizes groups + - Binary: is more complex. it created a decreasing size of containers to support better balancing. + - Atomic: it does not group tests at all and runs really each test case in a separate thread. -See `Pabot and DataDriver <#pabot-and-datadriver>`__ for more details. + See `Pabot and DataDriver <#pabot-and-datadriver>`__ for more details. -This can be set by ``optimize_pabot`` in Library import. + This can be set by ``optimize_pabot`` in Library import. """ + Equal = auto() Binary = auto() Atomic = auto() @@ -153,21 +155,21 @@ class PabotOpt(Enum): class TagHandling(Enum): """ -You can configure how to handle tags from the template in generated tests: + You can configure how to handle tags from the template in generated tests: -- ForceTags: Will add all tags of the template test to all data-driven test cases. -- UnsetTags: Will add only these tags from template test to the tests, that are not assigned to any of the test cases. -- DefaultTags: Will only add tags to data-driven test if no tag is set on that test. -- NoTags: Will not add any tags from the template to date-driven tests. + - ForceTags: Will add all tags of the template test to all data-driven test cases. + - UnsetTags: Will add only these tags from template test to the tests, that are not assigned to any of the test cases. + - DefaultTags: Will only add tags to data-driven test if no tag is set on that test. + - NoTags: Will not add any tags from the template to date-driven tests. """ + ForceTags = auto() UnsetTags = auto() DefaultTags = auto() NoTags = auto() - def debug(msg: Any, newline: bool = True, stream: str = "stdout"): if get_variable_value("${LOG LEVEL}") in ["DEBUG", "TRACE"]: logger.console(msg, newline, stream) diff --git a/src/DataDriver/xls_reader.py b/src/DataDriver/xls_reader.py index 4bc3152..dde223a 100644 --- a/src/DataDriver/xls_reader.py +++ b/src/DataDriver/xls_reader.py @@ -26,6 +26,6 @@ class xls_reader(xlsx_reader): def read_data_frame_from_file(self, dtype): - return pd.read_excel( - self.file, sheet_name=self.sheet_name, dtype=dtype - ).replace(nan, "", regex=True) + return pd.read_excel(self.file, sheet_name=self.sheet_name, dtype=dtype).replace( + nan, "", regex=True + )