RobotFramework框架提供了很多有用的开放API供我们使用,具体可以参考RobotFramework官方网站的开放API。
其中,下面的类和方法是比较常用的:
-
logger
module for test libraries’ logging purposes. -
deco
module with decorators test libraries can utilize. -
TestCaseFile
,TestDataDirectory
, andResourceFile
classes for parsing test data files and directories. In addition, a convenience factory methodTestData()
creates eitherTestCaseFile
orTestDataDirectory
objects based on the input. -
TestSuite
class for creating executable test suites programmatically andTestSuiteBuilder
class for creating such suites based on existing test data on the file system. -
SuiteVisitor
abstract class for processing testdata before execution. This can be used as a base for implementing a pre-run modifier that is taken into use with--prerunmodifier
commandline option. -
ExecutionResult()
factory method for reading execution results from XML output files andResultVisitor
abstract class to ease further processing the results.ResultVisitor
can also be used as a base for pre-Rebot modifier that is taken into use with--prerebotmodifier
commandline option. -
ResultWriter
class for writing reports, logs, XML outputs, and XUnit files. Can write results based on XML outputs on the file system, as well as based on the result objects returned by theExecutionResult()
or an executedTestSuite
.
下面是一个根据RobotFramework测试运行结果的XML文件解析RobotFramework测试用例数据的示例代码:
from xml.etree import ElementTree as xet
import numpy as np
import pandas as pd
import pylab
import os
from datetime import datetime
import matplotlib
matplotlib.use("Agg")
from matplotlib import pyplot as plt
if os.name == 'posix':
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
if os.name == 'nt':
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
plt.rcParams['savefig.dpi'] = 200
plt.rcParams['figure.dpi'] = 200
def plot_pie(sizes, labels, title, explode, file_name_to_save):
fig, ax = plt.subplots()
ax.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=False, startangle=0)
ax.axis('equal')
plt.title(title, fontsize=20, fontweight='bold')
plt.legend()
plt.savefig(file_name_to_save, dpi=200)
def plot_bar(cat1, cat2, labels, xlabel, ylabel, title, max_y, filename, width=0.35):
cat1 = cat1
cat2 = cat2
labels = labels
x = np.arange(len(cat1))
plt.bar(x, height=cat1, width=width, alpha=0.8, color="green", label="Passed")
plt.bar(x, height=cat2, width=width, color="red", label="Failed", bottom=cat1)
plt.ylim(0, max_y)
plt.ylabel(xlabel)
plt.xlabel(ylabel)
plt.xticks(x, labels)
pylab.xticks(rotation=45)
plt.title(title)
plt.legend()
plt.savefig(filename, dpi=200)
def parse_rfoutput_total(root):
for sub_child in root:
if sub_child.text == "Critical Tests":
labels = "Passed", "Failed"
sizes = [sub_child.attrib['pass'], sub_child.attrib['fail']]
explode = (0, 0.2)
title = "Critical Tests Execute Result"
filename = "./statistics/Critical_Tests_info.png"
plot_pie(sizes, labels=labels, title=title, explode=explode, file_name_to_save=filename)
if sub_child.text == "All Tests":
labels = "Passed", "Failed"
sizes = [sub_child.attrib['pass'], sub_child.attrib['fail']]
explode = (0, 0.2)
title = "All Tests Execute Result"
filename = "./statistics/All_Tests_info.png"
plot_pie(sizes, labels=labels, title=title, explode=explode, file_name_to_save=filename)
def parse_statistics_by_suite(root):
labels = list()
passed = list()
failed = list()
max_num = list()
for sub_child in root:
labels.append(sub_child.text)
passed.append(int(sub_child.attrib['pass']))
failed.append(int(sub_child.attrib['fail']))
max_num.append(int(sub_child.attrib['pass']) + int(sub_child.attrib['fail']))
print(max_num)
plot_bar(cat1=passed, cat2=failed,
labels=labels,
xlabel="测试套件", ylabel="用例数量",
title="Statistic By Suite", max_y=max(max_num),
filename="./statistics/Statistic_By_Suite.png"
)
def parse_statistic_by_casetags(root):
labels = list()
passed = list()
failed = list()
max_num = list()
for sub_child in root:
labels.append(sub_child.text)
passed.append(int(sub_child.attrib['pass']))
failed.append(int(sub_child.attrib['fail']))
max_num.append(int(sub_child.attrib['pass']) + int(sub_child.attrib['fail']))
print(max_num)
plot_bar(cat1=passed, cat2=failed,
labels=labels,
xlabel="TestCase Tag", ylabel="Case Number",
title="Statistic By Tag", max_y=max(max_num),
filename="./statistics/Statistic_By_Tag.png"
)
def parse_statistics_info(root):
for child in root:
if child.tag == "total":
parse_rfoutput_total(child)
if child.tag == "tag":
parse_statistic_by_casetags(child)
if child.tag == "suite":
parse_statistics_by_suite(child)
def parse_testcase_tree(root):
case_info = {
'CaseId': root.attrib['id'],
'CaseName': root.attrib['name'],
'CaseTags': set(),
'CaseStatus': None,
'CaseStartTime': None,
'CaseEndTime': None,
'CaseElapsedTime': None
}
for child in root:
if child.tag == "tags":
for sub in child:
case_info['CaseTags'].add(sub.text.strip())
if child.tag == "status":
case_info['CaseStatus'] = child.attrib['status']
case_info['CaseStartTime'] = child.attrib['starttime']
case_info['CaseEndTime'] = child.attrib['endtime']
case_running_elapsed_time = datetime.strptime(
case_info['CaseEndTime'], "%Y%m%d %H:%M:%S.%f"
) - datetime.strptime(
case_info['CaseStartTime'], "%Y%m%d %H:%M:%S.%f"
)
case_info['CaseElapsedTime'] = case_running_elapsed_time.total_seconds()
return case_info
def parse_rf_output(root, testcasetable):
if root.tag == 'test':
testcasetable.append(parse_testcase_tree(root))
elif root.tag == "statistics":
parse_statistics_info(root)
else:
for child in root:
parse_rf_output(child, testcasetable)
def get_latest_test_run_ouput(sourcedir='../TestResult/', sort_by='ctime'):
if os.path.isdir(sourcedir):
if len(os.listdir(sourcedir)) == 0:
raise FileNotFoundError("指定的目录中没有文件。")
else:
os.chdir(sourcedir)
files = [file for file in os.listdir(sourcedir) if \
file.startswith('output_') and file.endswith('.xml')]
if sort_by == 'ctime':
files.sort(
key=lambda f: os.path.getctime(sourcedir + os.sep + f)
)
elif sort_by == 'atime':
files.sort(
key=lambda f: os.path.getatime(sourcedir + os.sep + f)
)
elif sort_by == 'mtime':
files.sort(
key=lambda f: os.path.getmtime(sourcedir + os.sep + f)
)
else:
raise ValueError("排序方式不正确。")
return files[-1]
else:
raise NotADirectoryError("无此目录。")
if __name__ == '__main__':
testcasetable = list()
# file = get_latest_test_run_ouput(sourcedir="../TestResult")
xmltree = xet.parse("./output_183.xml")
root = xmltree.getroot()
parse_rf_output(root, testcasetable)
dt = pd.DataFrame(testcasetable)
dt.to_excel("./statistics/testcases.xlsx")