Campaigns

Campaigns shall be launched with the ‘run-campaign.py’ script.

usage: run-campaign.py [-h] [--config-file CONFIG_PATH]
                       [--config-value KEY VALUE] [--debug-class DEBUG_CLASS]
                       [--doc-only] [--issue-level-error ISSUE_LEVEL]
                       [--issue-level-ignored ISSUE_LEVEL]
                       [--outdir OUTDIR_PATH] [--dt-subdir]
                       [--extra-info ATTRIBUTE_NAME]
                       TEST_SUITE_PATH [TEST_SUITE_PATH ...]

Scenario campaign execution.

positional arguments:
  TEST_SUITE_PATH       Test suite file(s) to execute.

optional arguments:
  -h, --help            Show this help message and exit.
  --config-file CONFIG_PATH
                        Input configuration file path. This option may be
                        called several times.
  --config-value KEY VALUE
                        Single configuration value. This option may be called
                        several times.
  --debug-class DEBUG_CLASS
                        Activate debugging for the given class.
  --doc-only            Generate documentation without executing the test(s).
  --issue-level-error ISSUE_LEVEL
                        Define the issue level from and above which known
                        issues should be considered as errors. None by
                        default, i.e. all known issues are considered as
                        warnings.
  --issue-level-ignored ISSUE_LEVEL
                        Define the issue level from and under which known
                        issues should be ignored. None by default, i.e. no
                        known issue ignored by default.
  --outdir OUTDIR_PATH  Output directory to store test results into. Defaults
                        to the current directory.
  --dt-subdir           Do not store the test results directly in OUTDIR_PATH,
                        but within a subdirectory named with the current date
                        and time.
  --extra-info ATTRIBUTE_NAME
                        Scenario attribute to display for extra info when
                        displaying results. This option may be called several
                        times to display more info.

Test suite files

Test suite files are text files that describe the scenario files to execute, or not to execute.

Example from the demo.suite test suite file:

# This is a sample campaign description file.

# White-list:
+ *.py

# Black-list:
- htmltestlib.py
- run-demo.py
Test suite files syntax

Type of line

Syntax

Effects

Comment

Starts with a ‘#’ character.

No effect.

White list

Starts with a ‘+’ character, or no starter character, followed by a path or a glob-style pattern.

Describes one (or several) script path(s) of scenario(s) to execute.

When the path is relative, it is computed from the test suite file directory.

Black list

Starts with a ‘-’ character, followed by a path or a glob-style pattern.

Describes one (or several) script path(s) to remove from the white list constituted by the preceding lines.

When the path is relative, it is computed from the test suite file directory.

Tip

White-list lines after a black-list line may restore script paths avoided by the latter.

Campaign execution

Test suite files are executed one after the others, in the order given by the command line.

A summary of the tests executed is displayed in the end.

$ ./bin/run-campaign.py demo/demo.suite
CAMPAIGN
------------------------------------------------
  TEST SUITE 'demo/demo.suite'
  ----------------------------------------------
    Executing 'demo/commutativeaddition.py'
      DEBUG    Log file:    'out/commutativeaddition.log'
      DEBUG    JSON report: 'out/commutativeaddition.json'
    Executing 'demo/commutativeadditions.py'
      DEBUG    Log file:    'out/commutativeadditions.log'
      DEBUG    JSON report: 'out/commutativeadditions.json'
    Executing 'demo/handlers.py'
      DEBUG    Log file:    'out/handlers.log'
      DEBUG    JSON report: 'out/handlers.json'
    Executing 'demo/htmllogin.py'
      DEBUG    Log file:    'out/htmllogin.log'
      DEBUG    JSON report: 'out/htmllogin.json'
    Executing 'demo/loggingdemo.py'
      DEBUG    Log file:    'out/loggingdemo.log'
      DEBUG    JSON report: 'out/loggingdemo.json'

  END OF TEST SUITE 'demo/demo.suite'
  ----------------------------------------------
             Number of test cases: 5
         Number of tests in error: 0
    Number of tests with warnings: 0
                  Number of steps: 15/15
                Number of actions: 39/39
                Number of results: 2/2
                             Time: HH:MM:SS.mmmmmm

END OF CAMPAIGN
------------------------------------------------
          Number of test suites: 1

DEBUG    JUnit report: 'out/campaign.xml'
------------------------------------------------
INFO     TOTAL                                  Status      Steps    Actions    Results    Time
INFO     5 tests, 0 failed, 0 with warnings                 15/15      39/39        2/2    HH:MM:SS.mmmmmm
------------------------------------------------
INFO     demo/commutativeaddition.py           SUCCESS        4/4        4/4        1/1    HH:MM:SS.mmmmmm
INFO     demo/commutativeadditions.py          SUCCESS        3/3        3/3        0/0    HH:MM:SS.mmmmmm
INFO     demo/handlers.py                      SUCCESS        2/2        2/2        0/0    HH:MM:SS.mmmmmm
INFO     demo/htmllogin.py                     SUCCESS        1/1        3/3        1/1    HH:MM:SS.mmmmmm
INFO     demo/loggingdemo.py                   SUCCESS        5/5      27/27        0/0    HH:MM:SS.mmmmmm

Campaign reports

The --outdir option specifies the directory where the execution reports should be stored.

--dt-subdir option

In conjonction with it, the --dt-subdir option tells the ‘run-campaign.py’ launcher to create a date/time subdirectory in the output directory.

The date/time subdirectory is formed on the ‘YYYY-MM-DD_HH-MM-SS’ pattern.

For each scenario executed, a JSON report is stored in the output directory.

Eventually, a campaign report is generated in the XML JUnit format.

<?xml version="1.0" encoding="utf-8"?>
<testsuites actions-executed="39" actions-total="39" disabled="0" errors="0" failures="0" results-executed="2" results-total="2" steps-executed="15" steps-total="15" tests="5" time="SSS.mmmmmm">
	<testsuite actions-executed="39" actions-total="39" disabled="0" errors="0" failures="0" id="0" name="demo/demo.suite" results-executed="2" results-total="2" skipped="0" steps-executed="15" steps-total="15" tests="5" time="SSS.mmmmmm" timestamp="YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM">
		<testcase actions-executed="4" actions-total="4" classname="demo/commutativeaddition.py" name="demo/commutativeaddition.py" results-executed="1" results-total="1" status="SUCCESS" steps-executed="4" steps-total="4" time="SSS.mmmmmm">
			<link href="out/commutativeaddition.log" rel="log" type="text/plain"/>
			<link href="out/commutativeaddition.json" rel="report" type="application/json"/>
			<system-out>SCENARIO 'demo/commutativeaddition.py'
------------------------------------------------


STEP#1: Initial conditions (demo/commutativeaddition.py:18:CommutativeAddition.step000)
------------------------------------------------
    ACTION: Let a = 1, and b = 3
  EVIDENCE:   -&gt; a = 1
  EVIDENCE:   -&gt; b = 3

STEP#2: a + b (demo/commutativeaddition.py:25:CommutativeAddition.step010)
------------------------------------------------
    ACTION: Compute (a + b) and store the result as result1.
  EVIDENCE:   -&gt; result1 = 4

STEP#3: b + a (demo/commutativeaddition.py:32:CommutativeAddition.step020)
------------------------------------------------
    ACTION: Compute (b + a) and store the result as result2.
  EVIDENCE:   -&gt; result2 = 4

STEP#4: Check (demo/commutativeaddition.py:39:CommutativeAddition.step030)
------------------------------------------------
    ACTION: Compare result1 and result2.
    RESULT: result1 and result2 are the same.
  EVIDENCE:   -&gt; 4 == 4

END OF 'demo/commutativeaddition.py'
------------------------------------------------
             Status: SUCCESS
    Number of STEPs: 4/4
  Number of ACTIONs: 4/4
  Number of RESULTs: 1/1
               Time: HH:MM:SS.mmmmmm

</system-out>
		</testcase>
		<testcase actions-executed="3" actions-total="3" classname="demo/commutativeadditions.py" name="demo/commutativeadditions.py" results-executed="0" results-total="0" status="SUCCESS" steps-executed="3" steps-total="3" time="SSS.mmmmmm">
			<link href="out/commutativeadditions.log" rel="log" type="text/plain"/>
			<link href="out/commutativeadditions.json" rel="report" type="application/json"/>
			<system-out>SCENARIO 'demo/commutativeadditions.py'
------------------------------------------------


STEP#1: Both positive members (demo/commutativeadditions.py:16:CommutativeAdditions.step010)
------------------------------------------------
    ACTION: Launch the CommutativeAddition scenario with 4 and 5 for inputs.
      | SCENARIO 'demo/commutativeaddition.py'
      | ------------------------------------------------
      |
      | STEP#1: Initial conditions (demo/commutativeaddition.py:18:CommutativeAddition.step000)
      | ------------------------------------------------
      |     ACTION: Let a = 4, and b = 5
      |   EVIDENCE:   -&gt; a = 4
      |   EVIDENCE:   -&gt; b = 5
      |
      | STEP#2: a + b (demo/commutativeaddition.py:25:CommutativeAddition.step010)
      | ------------------------------------------------
      |     ACTION: Compute (a + b) and store the result as result1.
      |   EVIDENCE:   -&gt; result1 = 9
      |
      | STEP#3: b + a (demo/commutativeaddition.py:32:CommutativeAddition.step020)
      | ------------------------------------------------
      |     ACTION: Compute (b + a) and store the result as result2.
      |   EVIDENCE:   -&gt; result2 = 9
      |
      | STEP#4: Check (demo/commutativeaddition.py:39:CommutativeAddition.step030)
      | ------------------------------------------------
      |     ACTION: Compare result1 and result2.
      |     RESULT: result1 and result2 are the same.
      |   EVIDENCE:   -&gt; 9 == 9
      |
      | END OF 'demo/commutativeaddition.py'

STEP#2: Positive and negative members (demo/commutativeadditions.py:23:CommutativeAdditions.step020)
------------------------------------------------
    ACTION: Launch the CommutativeAddition scenario with -1 and 3 for inputs.
      | SCENARIO 'demo/commutativeaddition.py'
      | ------------------------------------------------
      |
      | STEP#1: Initial conditions (demo/commutativeaddition.py:18:CommutativeAddition.step000)
      | ------------------------------------------------
      |     ACTION: Let a = -1, and b = 3
      |   EVIDENCE:   -&gt; a = -1
      |   EVIDENCE:   -&gt; b = 3
      |
      | STEP#2: a + b (demo/commutativeaddition.py:25:CommutativeAddition.step010)
      | ------------------------------------------------
      |     ACTION: Compute (a + b) and store the result as result1.
      |   EVIDENCE:   -&gt; result1 = 2
      |
      | STEP#3: b + a (demo/commutativeaddition.py:32:CommutativeAddition.step020)
      | ------------------------------------------------
      |     ACTION: Compute (b + a) and store the result as result2.
      |   EVIDENCE:   -&gt; result2 = 2
      |
      | STEP#4: Check (demo/commutativeaddition.py:39:CommutativeAddition.step030)
      | ------------------------------------------------
      |     ACTION: Compare result1 and result2.
      |     RESULT: result1 and result2 are the same.
      |   EVIDENCE:   -&gt; 2 == 2
      |
      | END OF 'demo/commutativeaddition.py'

STEP#3: Both negative members (demo/commutativeadditions.py:30:CommutativeAdditions.step030)
------------------------------------------------
    ACTION: Launch the CommutativeAddition scenario with -1 and -7 for inputs.
      | SCENARIO 'demo/commutativeaddition.py'
      | ------------------------------------------------
      |
      | STEP#1: Initial conditions (demo/commutativeaddition.py:18:CommutativeAddition.step000)
      | ------------------------------------------------
      |     ACTION: Let a = -1, and b = -7
      |   EVIDENCE:   -&gt; a = -1
      |   EVIDENCE:   -&gt; b = -7
      |
      | STEP#2: a + b (demo/commutativeaddition.py:25:CommutativeAddition.step010)
      | ------------------------------------------------
      |     ACTION: Compute (a + b) and store the result as result1.
      |   EVIDENCE:   -&gt; result1 = -8
      |
      | STEP#3: b + a (demo/commutativeaddition.py:32:CommutativeAddition.step020)
      | ------------------------------------------------
      |     ACTION: Compute (b + a) and store the result as result2.
      |   EVIDENCE:   -&gt; result2 = -8
      |
      | STEP#4: Check (demo/commutativeaddition.py:39:CommutativeAddition.step030)
      | ------------------------------------------------
      |     ACTION: Compare result1 and result2.
      |     RESULT: result1 and result2 are the same.
      |   EVIDENCE:   -&gt; -8 == -8
      |
      | END OF 'demo/commutativeaddition.py'

END OF 'demo/commutativeadditions.py'
------------------------------------------------
             Status: SUCCESS
    Number of STEPs: 3/3
  Number of ACTIONs: 3/3
  Number of RESULTs: 0/0
               Time: HH:MM:SS.mmmmmm

</system-out>
		</testcase>
		<testcase actions-executed="2" actions-total="2" classname="demo/handlers.py" name="demo/handlers.py" results-executed="0" results-total="0" status="SUCCESS" steps-executed="2" steps-total="2" time="SSS.mmmmmm">
			<link href="out/handlers.log" rel="log" type="text/plain"/>
			<link href="out/handlers.json" rel="report" type="application/json"/>
			<system-out>SCENARIO 'demo/handlers.py'
------------------------------------------------

DEBUG    'scenario.before-test' handler called with test &lt;Handlers 'demo/handlers.py'&gt;
DEBUG    'scenario.before-step' handler called with step &lt;StepDefinition 'Handlers.step010'&gt;

STEP#1: `UserEvent.FOO` event triggering (demo/handlers.py:55:Handlers.step010)
------------------------------------------------
    ACTION: Trigger the `UserEvent.FOO` event, with the following parameters: a=1 and b='bar'.
              DEBUG    'foo' handler called with {'a': 1, 'b': 'bar'}
DEBUG    'scenario.after-step' handler called with step &lt;StepDefinition 'Handlers.step010'&gt;
DEBUG    'scenario.before-step' handler called with step &lt;StepDefinition 'Handlers.step020'&gt;

STEP#2: `UserEvent.FOO` event triggering (demo/handlers.py:61:Handlers.step020)
------------------------------------------------
    ACTION: Trigger the `UserEvent.FOO` event, with the following parameters: a=2 and b='baz'.
              DEBUG    'foo' handler called with {'a': 2, 'b': 'baz'}
DEBUG    'scenario.after-step' handler called with step &lt;StepDefinition 'Handlers.step020'&gt;
DEBUG    'scenario.after-test' handler called with test &lt;Handlers 'demo/handlers.py'&gt;

END OF 'demo/handlers.py'
------------------------------------------------
             Status: SUCCESS
    Number of STEPs: 2/2
  Number of ACTIONs: 2/2
  Number of RESULTs: 0/0
               Time: HH:MM:SS.mmmmmm

</system-out>
		</testcase>
		<testcase actions-executed="3" actions-total="3" classname="demo/htmllogin.py" name="demo/htmllogin.py" results-executed="1" results-total="1" status="SUCCESS" steps-executed="1" steps-total="1" time="SSS.mmmmmm">
			<link href="out/htmllogin.log" rel="log" type="text/plain"/>
			<link href="out/htmllogin.json" rel="report" type="application/json"/>
			<system-out>SCENARIO 'demo/htmllogin.py'
------------------------------------------------


STEP#1: Login screen (demo/htmllogin.py:13:TestLoginPage.step010_loginscreen)
------------------------------------------------
    ACTION: Type the login.
              INFO     [edit[@id='login']] Typing text 'john'
    ACTION: Type the password.
              INFO     [edit[@id='password']] Typing text '0000'
    ACTION: Click on the OK button.
              INFO     [edit[@id='submit']] Clicking on the button
    RESULT: The login page says hello to the user.

END OF 'demo/htmllogin.py'
------------------------------------------------
             Status: SUCCESS
    Number of STEPs: 1/1
  Number of ACTIONs: 3/3
  Number of RESULTs: 1/1
               Time: HH:MM:SS.mmmmmm

</system-out>
		</testcase>
		<testcase actions-executed="27" actions-total="27" classname="demo/loggingdemo.py" name="demo/loggingdemo.py" results-executed="0" results-total="0" status="SUCCESS" steps-executed="5" steps-total="5" time="SSS.mmmmmm">
			<link href="out/loggingdemo.log" rel="log" type="text/plain"/>
			<link href="out/loggingdemo.json" rel="report" type="application/json"/>
			<system-out>SCENARIO 'demo/loggingdemo.py'
------------------------------------------------


STEP#1: Logging with the main logger (demo/loggingdemo.py:22:LoggingScenario.step010)
------------------------------------------------
    ACTION: Log messages of different log levels with the main logger.
              ERROR    This is an error!!!
              WARNING  This is a warning!
              INFO     This is information.
              DEBUG    This is debug.

STEP#2: Logging with the scenario instance (demo/loggingdemo.py:31:LoggingScenario.step020)
------------------------------------------------
    ACTION: Log messages of different log levels with the scenario itself.
              ERROR    [demo/loggingdemo.py] This is an error!!!
              WARNING  [demo/loggingdemo.py] This is a warning!
              INFO     [demo/loggingdemo.py] This is information.
              DEBUG    [demo/loggingdemo.py] This is debug.

STEP#3: Logging with a class logger (demo/loggingdemo.py:40:LoggingScenario.step030)
------------------------------------------------
    ACTION: Log messages of different log levels with the class logger instance.
              ERROR    [My logger] This is an error!!!
              WARNING  [My logger] This is a warning!
              INFO     [My logger] This is information.
    ACTION: Activate debugging for the class logger instance.
    ACTION: Log a debug message again with the class logger instance.
              DEBUG    [My logger] This is debug again.

STEP#4: Class logger indentation (demo/loggingdemo.py:55:LoggingScenario.step110)
------------------------------------------------
    ACTION: Log something with the class logger.
              INFO     [My logger] Hello
    ACTION: Push indentation to the class logger.
    ACTION: Log something with the class logger.
              INFO     [My logger]     Hello
    ACTION: Push indentation to the class logger.
    ACTION: Log something with the class logger.
              INFO     [My logger]         Hello
    ACTION: Push indentation to the class logger.
    ACTION: Log something with the class logger.
              INFO     [My logger]             Hello
    ACTION: Pop indentation from the class logger.
    ACTION: Log something with the class logger.
              INFO     [My logger]         Hello
    ACTION: Reset the class logger indentation.
    ACTION: Log something with the class logger.
              INFO     [My logger] Hello

STEP#5: Main logger indentation (demo/loggingdemo.py:76:LoggingScenario.step120)
------------------------------------------------
    ACTION: Log something with the main logger.
              INFO     Hello
    ACTION: Push indentation to the main logger.
    ACTION:     Log something with the main logger.
                  INFO     Hello
    ACTION:     Push indentation to the main logger.
    ACTION:         Log something with the main logger.
                      INFO     Hello
    ACTION:         Push indentation to the main logger.
    ACTION:             Log something with the main logger.
                          INFO     Hello
    ACTION:             Pop indentation from the main logger.
    ACTION:         Log something with the main logger.
                      INFO     Hello
    ACTION:         Reset the main logger indentation.
    ACTION: Log something with the main logger.
              INFO     Hello

END OF 'demo/loggingdemo.py'
------------------------------------------------
             Status: SUCCESS
    Number of STEPs: 5/5
  Number of ACTIONs: 27/27
  Number of RESULTs: 0/0
               Time: HH:MM:SS.mmmmmm

</system-out>
		</testcase>
	</testsuite>
</testsuites>

XML JUnit format

A reference documentation could not be found for the XML JUnit format.

In spite of, the [CUBIC] page can be noted as one of the best resources on that topic.