Integrating JUNIT with TestRail
Pytest (opens in a new tab) is a popular Python testing framework which is used by many teams for both unit and end-to-end testing using tools such as REST Assured, Selenium WebDriver, Playwright, etc.
Railflow provides a convenient Pytest plugin which enables users to integrate their Pytest project with TestRail in a variety of flexible ways. Railflow Pytest plugin provides the following capabilities
Test Mapping
: Map Pytest tests existing tests in TestRailAttach Screenshots
: Attach screenshots and arbitrary attachments to the test case results in TestRail.Custom Fields
: Support for TestRail custom fields.TestRail Entities
: Update / Create Test Plans, Runs, Milestone, Tests, ResultsCI Application
: Support for Jenkins, TeamCity, Gitlab, Github, etc.
Getting Started
The Railflow Pytest plugin produces an enriched json test report. This report contains TestRail metadata, screenshot, etc. This report is then processed by Railflow CI Plugins or the CLI to upload the tests and test results to TestRail.
Railflow pytest plugin (opens in a new tab) is available on PyPI and can be easily installed using pip and can also be added to the project's requirements.txt
file.
pip install pytest-railflow-testrail-reporter
Railflow Markers
The Railflow Pytest plugins provides a number of markers at the class and function level. Class level markers are inherited by all the test functions in the class. Function level markers can be used to override the class level markers. This behavior provides a great deal of flexibility in mapping Pytest tests to TestRail test cases.
Attribute Name | Description |
---|---|
title | Name of the test suite or test case |
case_type | Case type in TestRail, e.g.: Automated, Compatibility, etc... |
case_priority | Case type in TestRail, e.g.: Critical, High, etc... |
case_fields | Values for custom case fields in TestRail, e.g.: ['field1=value1','field2=value2'] |
result_fields | Values for result fields in TestRail, e.g.: ['field1=value1','field2=value2'] |
jira_ids | Jira IDs.These values will be populated as a case field 'refs'. Should input as an array of strings, e.g.: ['jid1','jid2'] |
testrail_ids | IDs of test cases in TestRail. Should input as an array of integers, e.g.: [1,2,3] |
smart_failure_assignment | Array of TestRail users to automatically assign failed test cases. Should input as a string array, e.g.: ['[email protected]','[email protected]'] |
Screenshot and Attachments
Adding Attachments
The testrail_add_screenshot
fixture can be used to add arbitrary attachments into the test report:
def test_add(testrail_add_screenshot):
a = 3
b = 2
c = a + b
assert c == 5
testrail_add_screenshot("image.png")
Automatic Screenshot for Selenium Tests Railflow plugin supports Pytest Splinter (opens in a new tab) and if your selenium/appium tests use pytest-splinter plugin, then Railflow plugin automatically takes screenshots of failed tests and upload them to TestRail (yes, really)
import pytest
@pytest.mark.railflow(
testrail_ids=["C134"],
case_type="Automated"
)
def test_google(browser):
browser.visit("https://www.google.com")
browser.fill('q', 'splinter - python acceptance testing for web applications')
# Find and click the 'search' button
button = browser.find_by_name('btnK')
# Interact with elements
button.click()
assert browser.is_text_present('splinter.cobrateam.info'), "splinter.cobrateam.info wasn't found."
Screenshots and attachments
When using Selenium WebDriver, it is common to take screenshots of the browser window when a test fails. Railflow provides utility classes and several static methods
for taking automatic screenshot so that they can also be uploaded to TestRail along with the failure exception message
addAttachment(File attachmentFile)
: Adds arbitrary attachment file to the XML report.addAttachment(final String name, final InputStream inputStream)
: Adds an attachment file with given name and contents of inputStreamaddAttachment(final String name, final byte[] data)
: Adds an attachment file with given name and content specified by the given byte array
Class Level Annotations
Name | Description |
---|---|
title | name for the subsection which contains the test in TestRail, if not defined |
testrailIds | ignored |
caseFields | array of test case field label/value pairs, e.g.@CustomField(name="My custom case field", value="Railflow rocks") |
resultFields | array of test result field label/value pairs, e.g.@CustomField(name="My custom result field", value="Railflow rocks") |
caseType | name of the case type for a test in TestRail, e.g.Automated |
casePriority | name of the case priority for a test in TestRail, e.g.High |
jiraIds | array of Jira issue IDs, which will be set as refs in TestRail |
smartFailureAssignment | array of user email IDs, each failed test in the class will be assigned to one of these users in a round-robin fashion |
Annotation package provides io.railflow.annotations.Railflow
annotation which can be applied to test class or test method.
The io.railflow.annotations.Railflow
annotation has a number of attributes which have slightly different meaning based on class level or method level applicaiton.
Attributes of the Railflow annotation on method level override similar attributes of the Railflow annotation on class level.
Class Level Annotations
Name | Description |
---|---|
title | name for the subsection which contains the test in TestRail, if not defined |
testrailIds | ignored |
caseFields | array of test case field label/value pairs, e.g.@CustomField(name="My custom case field", value="Railflow rocks") |
resultFields | array of test result field label/value pairs, e.g.@CustomField(name="My custom result field", value="Railflow rocks") |
caseType | name of the case type for a test in TestRail, e.g.Automated |
casePriority | name of the case priority for a test in TestRail, e.g.High |
jiraIds | array of Jira issue IDs, which will be set as refs in TestRail |
smartFailureAssignment | array of user email IDs, each failed test in the class will be assigned to one of these users in a round-robin fashion |
Configure Surefire Plugin (JUnit 4 only)
Configuring the surefire plugin and adding the Railflow dependency will enable the junit project to generate an enriched junit schema compliant report during mvn test
. This report contains all the test metadata added via annotation and will be consumed by Railflow CI plugins or CLI.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.22.2</version>
</dependency>
</dependencies>
<configuration>
<properties>
<property>
<name>listener</name>
<value>io.railflow.annotations.junit.RailflowJunit4Listener</value>
</property>
</properties>
</configuration>
</plugin>
Register Railflow listener (JUnit 4 only)
Add io.railflow.annotations.junit.RailflowJunit4Listener
Junit4 listener in JUnitCore
object in your test runner:
import org.junit.runner.JUnitCore;
import io.railflow.annotations.junit.RailflowJunit4Listener;
public class MyTestRunner {
public static void main(String args[]) {
JUnitCore runner = new JUnitCore();
runner.addListener(new RailflowJunit4Listener());
runner.run(YourTestClass.class);
}
}
You can change the default locatio of railflow_report.xml
file using the raillfow report_dir
property.
mvn clean test -Dio.railflow.report_dir=target\surefire-reports
Railflow Annotations
The Java Annotation package provides io.railflow.annotations.Railflow
annotation which can be applied to test class or test method.
The io.railflow.annotations.Railflow
annotation has a number of attributes which have slightly different meaning based on class level or method level applicaiton.
Attributes of the Railflow annotation on method level override similar attributes of the Railflow annotation on class level.
Class Level Annotations
Name | Description |
---|---|
title | name for the subsection which contains the test in TestRail, if not defined |
testrailIds | ignored |
caseFields | array of test case field label/value pairs, e.g.@CustomField(name="My custom case field", value="Railflow rocks") |
resultFields | array of test result field label/value pairs, e.g.@CustomField(name="My custom result field", value="Railflow rocks") |
caseType | name of the case type for a test in TestRail, e.g.Automated |
casePriority | name of the case priority for a test in TestRail, e.g.High |
jiraIds | array of Jira issue IDs, which will be set as refs in TestRail |
smartFailureAssignment | array of user email IDs, each failed test in the class will be assigned to one of these users in a round-robin fashion |
Method Level Annotations
Name | Description |
---|---|
title | test title, if not specified, test method name is used |
testrailIds | array of TestRail test IDs into which the result of this method will be added |
caseFields | array of test case field label/value pairs, e.g.@CustomField(name="My custom case field", value="Railflow rocks") |
resultFields | array of test result field label/value pairs, e.g.@CustomField(name="My custom result field", value="Railflow rocks") |
caseType | name of the case type for a test in TestRail, e.g.Automated |
casePriority | name of the case priority for a test in TestRail, e.g.High |
jiraIds | array of Jira issue IDs, which will be set as refs in TestRail |
smartFailureAssignment | user email ID to assign failed test result to |
Screenshots and attachments
When using Selenium WebDriver, it is common to take screenshots of the browser window when a test fails. Railflow provides utility classes and several static methods
for taking automatic screenshot so that they can also be uploaded to TestRail along with the failure exception message
addAttachment(File attachmentFile)
: Adds arbitrary attachment file to the XML report.addAttachment(final String name, final InputStream inputStream)
: Adds an attachment file with given name and contents of inputStreamaddAttachment(final String name, final byte[] data)
: Adds an attachment file with given name and content specified by the given byte array
Railflow CLI / CI Plugins
The resulting railflow_report.xml
report file can be processed and the tests and test results uploaded to TestRail using Railflow CLI or CI plugins.
npx railflow -k ABCDE-12345-FGHIJ-67890 -url https://testrail.your-server.com/ -u testrail-username -p testrail-password -pr "Railflow Demo" -path Master/section1/section2 -f junit -r target/surefire-reports/railflow_report.xml
Jenkins plugin
TeamCity plugin
Annotations Examples
Class Level
package io.railflow.annotations.demo;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.junit.Test;
import io.railflow.annotations.CustomField;
import io.railflow.annotations.Railflow;
import io.railflow.annotations.junit.CurrentTest;
@Railflow(title = "Railflow on the class level", jiraIds = {"ISSUE-42", "ISSUE-43"}, caseType = "Automated", casePriority = "Critical",
caseFields = {@CustomField(name = "required text field", value = "class value"), @CustomField(name = "estimate", value = "42s")},
resultFields = {@CustomField(name = "Custom field", value = "result from class annotations")},
smartFailureAssignment = { "[email protected]", "[email protected]" })
public class RailflowDemoTest {
@Test
public void test() throws IOException {
CurrentTest.addAttachment("my log.txt", "something".getBytes(StandardCharsets.UTF_8));
}
@Test
public void test_failed() throws IOException {
CurrentTest.addAttachment("my log.txt", "something".getBytes(StandardCharsets.UTF_8));
Assert.fail("oops");
}
}
Results in TestRail after uploading generated railflow_report.xml
Method Level
package io.railflow.annotations;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.junit.Assert;
import org.junit.Test;
import io.railflow.annotations.CustomField;
import io.railflow.annotations.junit.CurrentTest;
public class RailflowDemoTest {
@Railflow(title = "Railflow on the method level", jiraIds = {"ISSUE-44", "ISSUE-45"}, caseType = "Performance", casePriority = "High",
caseFields = {@CustomField(name = "required text field", value = "method value"), @CustomField(name = "estimate", value = "24s")},
resultFields = {@CustomField(name = "Custom field", value = "result from annotation on method")}, smartFailureAssignment = {"[email protected]"})
@Test
public void test() throws IOException {
CurrentTest.addAttachment("my log.txt", "something".getBytes(StandardCharsets.UTF_8));
}
@Test
public void test_failed() throws IOException {
CurrentTest.addAttachment("my log.txt", "something".getBytes(StandardCharsets.UTF_8));
Assert.fail("oops");
}
}
Results in TestRail after uploading generated railflow_report.xml
CLI Reference
Railflow CLI will automatically create tests, runs, plans, milestones, etc. if they do not exist.
Environment Variables:
To avoid exposing sensitive information like TestRail URL, License, username, and password in CLI arguments, users can set the following environment variables: RAILFLOW_LICENSE
, RAILFLOW_TR_URL
, RAILFLOW_TR_USER
, RAILFLOW_TR_PASSWORD
. Railflow CLI will always check these environment variables at run time.
Use double quotes for argument values with spaces. Example: --project "demo project"
Key | Required | Description | Example |
---|---|---|---|
-v, --version | No | Outputs Railflow version number | -v |
-k, --key | -k or -l | (online activation) License key. Can be set with RAILFLOW_LICENSE environment variable | -k XXXXX-XXXXX-XXXXX-XXXXX |
-l, --license-file | -k or -l | (offline activation) File path or remote url license file | -l /files/ActivationFile.skm |
-url, --url | Yes | TestRail instance URL. Can be set with RAILFLOW_TR_URL environment variable | -url https://example.testrail.io (opens in a new tab) |
-u, --username | Yes | TestRail username. Can be set with RAILFLOW_TR_USER environment variable | -u test-username |
-p, --password | Yes | TestRail password or API Key. Can be set with RAILFLOW_TR_PASSWORD environment variable | -p XtpHXiPLEODyhF |
-pr, --project | Yes | TestRail project name | -pr "example project" |
-path, --test-path | Yes | TestRail test cases path | -path "Section1/subsection2/ShoppingCart |
-f, --format | Yes | Report format: JUnit, JUnit-Steps, TestNg, TestNg-Steps, Cucumber, NUnit, NUnit-SpecFlow, Allure, Robot, TRX, xUnit, PyTest-Railflow, Playwright (case insensitive) | -f junit |
-r, --report-files | Yes | The file path(s) to the test report file(s) generated during the build. User can pass multiple values separated with spaces. Ant-style patterns such as **/surefire-reports/*.xml can be used. E.g. use target/surefire-reports/*.xml to capture all XML files in target/surefire-reports directory. | -r target/surefire-reports/*.xml target/failsafe-reports/*.xml |
-sm, --search-mode | Yes | Specifies the test case lookup algorithm. name: search for test case matching the name within the entire test suite. If test case found, update the test case. If test case not found, create a new test case within specified -path path: search for test case matching the name within the specified -path . If test case found, update the test case. If test case not found, create a new test case within specified -path | -sm path |
-px, --proxy | No | HTTP or SOCKS proxy configuration E.g. socks://username:[email protected]:1080 | -px socks://username:[email protected]:1080 |
-t, --timeout | No | Upload timeout (seconds) | -t 10 |
-tr, --test-run | No | TestRail test run name | -tr "Chrome Regression Run" |
-tp, --test-plan | No | TestRail test plan Name | -tp "Shopping Cart Test Plan" |
-mp, --milestone-path | No | TestRail milestone path | -mp Milestone1/Milestone2 |
-cf, --case-fields | No | TestRail test case custom fields. The format is [Field label]=[value] pairs, separated with space. E.g. "Case Field 1=value 1" "Case Field 2=value 2" ... | -cf "Case Field 1=value 1" "Case Field 2=value 2" |
-rf, --result-fields | No | TestRail test result custom fields. The format is [Field label]=[value] pairs, separated with space. E.g. "Result Field 1=value 1" "Result Field 2=value 2" ... | -rf "Result Field 1=value 1" "Result Field 2=value 2" |
-a, --assign | No | Smart Test Failure Assignment. Comma-separated list of TestRail users (email addresses). Railflow will assign failures based on a round robin algorithm. | -a [email protected],[email protected] |
-af, --assign-file | No | Smart Test Failure Assignment. File path containing list of TestRail users (email addresses). Note: One user per line | -af /assignees.txt |
-cn, --config-names | No | TestRail test plan configuration options. Configuration format is: [config_group_name]/[config_name]. E.g. "Operating Systems/Linux" "Browsers/Chrome" ... | -cn "Operating Systems/Linux" "Browsers/Chrome" |
-cr, --close-run | No | If Railflow should close the corresponding run after uploading test results | -cr |
-cp, --close-plan | No | If Railflow should close the corresponding plan after uploading test results | -cp |
-dg, --disable-grouping | No | If Railflow should ignore report structure and just upload all tests into a folder which is set by test-path parameter | -dg |
-tn, --template-name | No | The name of a template to use in TestRail. If it is not set, 'Test Case (Steps)' or the default one will be used | -tn "Test Case (Steps)" |
-cst, --case-type | No | The name of a type for cases | -cst other |
-csp, --case-priority | No | The name of a priority for cases | -csp medium |
-th, --thread-number | No | The number of concurrent threads for exporting data. Default is 4 | -th 8 |
-um, --upload-mode | No | Upload mode. Available values are: 0 (default) - create new test cases and do not overwrite existing ones; 1 - create new cases and overwrite existing ones; 2 - do not create new cases and overwrite existing ones; 3 - do not create new cases and do not overwrite existing ones | -um 1 |
-csf, --case-search-field | No | The name of the case field in TestRail which will be using for searching for existing test cases instead of test case title | -csf "Custom field" |
-ds, --disable-stats | No | If Railflow should disable collecting usage and error logs | -ds |
-fqtn, --fully-qualified-test-name | No | If checked, Railflow will use fully qualified test names from the report files for test names in TestRail | -fqtn |
-us, --untested-status | No | The name of the status to use in TestRail for untested/skipped tests | -us Skipped |
-ams, --attachment-max-size | No | Maximum size of an attachment. Can be set in Gb, Mb, Kb or b. If the unit is not provided considered as Mb. E.g. 1Gb, 2, 20Kb, 3Mb | -ams 1Gb |
-atw, --attachment-type-whitelist | No | The comma-separated list of file extensions which are allowed to upload. E.g. json, .html, .xml | -atw "json, .html, .xml" |
-atb, --attachment-type-blacklist | No | The comma-separated list of file extensions which are not allowed to upload. E.g. json, .html, .xml | -atb "json, .html, .xml" |
-nr, --no-run | No | Do not create or update Test Run in TestRail | -nr |
-tfn, --tags-field-name | No | The name of a test case field which will be holding tags from the report file if any. E.g. Cucumber Tags | -tfn "Cucumber Tags" |
-h, --help | No | Show the help information | -h |