robotframework笔记22
创建测试库
支持的编程语言
机器人框架本身是用写的 Python 和自然的测试 库扩展它可以使用相同的实现 语言。 运行时框架上 Jython ,图书馆也可以 实现使用 Java 。 纯Python代码Python和工作 Jython,假设它不使用语法或模块 可在Jython。 当使用Python,也是可能的 实现与C库使用 Python C API ,尽管它是 往往更容易与C代码从Python库使用 ctypes 模块。
图书馆使用这些支持本地语言可以实现 也作为包装器使用其他功能实现 编程语言。 这种方法的一个很好的例子 远程 图书馆 外部运行,另一个广泛使用的方法 脚本或工具作为单独的进程。
提示
Python教程对于机器人框架测试库开发人员 覆盖足够的Python语言开始编写测试 图书馆使用它。 它还包含一个简单的示例库 和测试用例,您可以执行,否则调查 在您的机器上。
不同的测试库api
机器人框架有三个不同的测试库api。
静态API
最简单的方法是在一个模块(在Python)或一个类 (在Python或Java)方法直接映射 关键字的名字 。 关键字也一样的 参数 作为 实现它们的方法。 关键字 报告失败 与 例外, 日志 通过编写到标准输出,可以 返回 值 使用 返回
声明。
动态API
动态库的类实现方法的名字 他们实现的关键字,另一个方法来执行一个命名 关键字与给定的参数。 的名称关键字来实现,如 以及他们是如何执行,可以动态地确定 运行时,但报告状态、日志记录和返回值 同样是在静态API。
混合API
这是一个静态和动态API之间的混合。 图书馆是 类方法告诉他们关键字实现,但是 这些关键字必须直接可用。 一切除了 发现关键字实现的相似 静态API。
所有这些api是本章中描述。 一切都是基于 静态API是如何工作的,首先讨论了其功能。 如何 的 动态库的API 和 复合图书馆的API 不同于它 然后自己的章节中讨论。
在本章的例子主要是使用Python,但他们 为纯java开发人员也应该很容易理解。 在那些 一些api有分歧的情况下,两种用法都解释 足够的例子。
创建测试库类或模块
测试库可以作为Python模块和Python或Java实现 类。
测试库的名字
一个测试库的名称时使用一个库是进口的 一样的模块或类实现它的名称。 为 例子,如果你有一个Python模块 MyLibrary
(即, 文件 MyLibrary.py ),它将创建一个库的名字 MyLibrary。 同样,一个Java类 YourLibrary
,当 它不是在任何包,创建一个库的确切名称。
Python类总是在一个模块中。 如果一个类的名称 实现图书馆的名称是一样的模块,机器人 框架允许删除导入的类名 图书馆。 例如,类 MyLib
在 MyLib.py 文件可以用作图书馆只有名字 MyLib 。 这也 例如,与子,如果 parent.MyLib
模块 有类 MyLib
,它只使用进口 parent.MyLib 的工作原理。 如果模块名和类名不同,图书馆必须 使用使用模块和类名,如mymodule.MyLibrary 或 parent.submodule.MyLib 。
Java类在非默认包必须被使用 全名。 例如,类 MyLib
在 com.mycompany.myproject
包必须进口的名字 com.mycompany.myproject.MyLib 。
请注意
将类名与子只能在机器人框架 2.8.4和更新。 您还需要包括与早期版本 类名等 parent.MyLib.MyLib 。
提示
如果图书馆的名字很长,例如当Java 包名称很长,建议给图书馆 通过使用简单的别名 与名语法 。
提供的参数测试库
所有测试库作为类可以实现参数。 这些 参数设置表中指定库名称后, 当机器人框架导入库的创建一个实例, 将它们传递给它的构造函数。 图书馆作为一个模块实现 不带任何参数,所以尝试使用那些会导致错误。
图书馆所需的参数的数量是一样的 参数的数量被图书馆的接受 构造函数。 默认值和变量数量的参数工作 类似与 关键字参数 ,除了 没有变量参数对Java库的支持。 传递的参数 图书馆以及图书馆名称本身,可以指定 使用变量,所以可以改变它们,例如,从 命令行。
*** Settings ***
Library MyLibrary 10.0.0.1 8080
Library AnotherLib ${VAR}
实现示例,第一个在Java、Python和第二 在上面的例子中使用的库:
from example import Connection
class MyLibrary:
def __init__(self, host, port=80):
self._conn = Connection(host, int(port))
def send_message(self, message):
self._conn.send(message)
public class AnotherLib {
private String setting = null;
public AnotherLib(String setting) {
setting = setting;
}
public void doSomething() {
if setting.equals("42") {
// do something ...
}
}
}
测试库范围
图书馆实现类可以有一个内部状态,可以 被改变通过关键词和参数的构造函数 图书馆。 因为政府会影响关键词如何行为,它 变化是非常重要的,以确保一个测试用例不 意外地影响其他测试用例。 这种依赖关系 创建不易调试的问题,例如,当新的测试用例 添加和使用图书馆不一致。
机器人框架试图保持独立于每个测试用例 其他:默认情况下,它会创建新实例的测试库 每一个测试用例。 然而,这种行为并不总是可取的, 因为有时测试用例应该能够共享一个共同的 状态。 此外,所有库没有状态和创建 其中新实例是不需要的。
测试库可以控制创建新的库时 类属性 ROBOT_LIBRARY_SCOPE
。 这个属性必须 一个字符串,它可以有以下三个值:
测试用例
- 为每个测试用例创建一个新的实例。 一个可能的套件设置 和套房拆卸共享另一个实例。 这是默认的。
测试套件
- 创建一个新的实例为每个测试套件中。 体现测试 套房,从测试用例创建文件和包含的测试用例 自己的实例,和高级套房都得到自己的实例 可能的设置和拆解。
全球
- 只有一个实例被创建在整个测试执行它 是共享的所有测试用例和测试套件。 库创建的 模块总是全局的。
请注意
如果一个库是多次与不同的进口 参数 , 每次创建一个新实例范围无关。
当 测试套件
或 全球
使用范围与测试 库有一个状态,建议图书馆有一些 特殊关键字清理状态。 这个关键字就可以 使用,例如,在一个套件安装或拆卸,以确保测试 情况下在接下来的测试套件可以从一个已知状态。 例如, SeleniumLibrary 使用 全球
范围,使 使用相同的浏览器,而无需在不同的测试用例 重新打开它,它也有 关闭所有浏览器 关键字为 轻松关闭所有打开的浏览器。
Python库使用的例子 测试套件
范围:
class ExampleLibrary:
ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
def __init__(self):
self._counter = 0
def count(self):
self._counter += 1
print self._counter
def clear_counter(self):
self._counter = 0
示例Java库使用 全球
范围:
public class ExampleLibrary {
public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
private int counter = 0;
public void count() {
counter += 1;
System.out.println(counter);
}
public void clearCounter() {
counter = 0;
}
}
指定库版本
当一个测试库使用,机器人框架试图 确定它的版本。 然后写进了这个信息 syslog 提供调试信息。 库文件的工具 Libdoc 入关键字也写这个信息 它所产生的文件。
版本信息读取属性 ROBOT_LIBRARY_VERSION
类似地, 测试库范围 是 读取 ROBOT_LIBRARY_SCOPE
。 如果 ROBOT_LIBRARY_VERSION
试图不存在,信息 被读取 __version__
属性。 这些属性必须 类或模块属性,这取决于图书馆 实现为一个类或一个模块。 对于Java库的版本 必须声明为属性 静态最终
。
Python模块使用一个例子 __version__
:
__version__ = '0.1'
def keyword():
pass
一个Java类使用 ROBOT_LIBRARY_VERSION
:
public class VersionExample {
public static final String ROBOT_LIBRARY_VERSION = "1.0.2";
public void keyword() {
}
}
指定文档格式
从机器人框架2.7.5库文档的工具 Libdoc 支持多种格式的文档。 如果你想使用 机器人框架的自己的 文档格式 ,您可以指定 在源代码中使用的格式 ROBOT_LIBRARY_DOC_FORMAT
属性 同样作为 范围 和 版本 和他们自己的设置吗 ROBOT_LIBRARY_ *
属性。
可能不区分大小写的值的文档格式 机器人
(默认), HTML
, 文本
(纯文本), 和 休息
( reStructuredText )。 使用 休息
格式要求 的 docutils 模块安装时生成的文档。
设置文档格式如下面的Python和 Java示例使用reStructuredText和HTML格式,分别。 看到 记录库 节和 Libdoc 章的更多信息 记录测试库。
"""A library for *documentation format* demonstration purposes.
This documentation is created using reStructuredText__. Here is a link
to the only \`Keyword\`.
__ http://docutils.sourceforge.net
"""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def keyword():
"""**Nothing** to see here. Not even in the table below.
======= ===== =====
Table here has
nothing to see.
======= ===== =====
"""
pass
/**
* A library for <i>documentation format</i> demonstration purposes.
*
* This documentation is created using <a href="http://www.w3.org/html">HTML</a>.
* Here is a link to the only `Keyword`.
*/
public class DocFormatExample {
public static final String ROBOT_LIBRARY_DOC_FORMAT = "HTML";
/**<b>Nothing</b> to see here. Not even in the table below.
*
* <table>
* <tr><td>Table</td><td>here</td><td>has</td></tr>
* <tr><td>nothing</td><td>to</td><td>see.</td></tr>
* </table>
*/
public void keyword() {
}
}
图书馆作为侦听器
监听器接口 允许外部听众得到通知 测试执行。 例如,他们被称为套件时,测试,和关键词 开始和结束。 有时这样的通知为测试也很有用 图书馆,他们可以通过使用自定义侦听器注册ROBOT_LIBRARY_LISTENER
属性。 这个属性的值 应该使用侦听器的一个实例,可能图书馆本身。 的更多信息和示例 测试库作为监听器 部分。
创建静态关键字
什么方法被认为是关键字
当使用静态库API时,机器人框架使用反射 找出公共方法库类或模块 实现了。 这将排除所有方法从一个下划线, 也与Java库的方法只有在实现 java . lang . object
将被忽略。 所有的方法都没有 忽略了被认为是关键字。 例如,Python和Java 库下面实现单一的关键词 我的关键字 。
class MyLibrary:
def my_keyword(self, arg):
return self._helper_method(arg)
def _helper_method(self, arg):
return arg.upper()
public class MyLibrary {
public String myKeyword(String arg) {
return helperMethod(arg);
}
private String helperMethod(String arg) {
return arg.toUpperCase();
}
}
图书馆作为一个Python模块实现时,它也 可能限制方法是使用Python的关键词 __all__
属性。 如果 __all__
使用,唯一的方法吗 中列出的关键词。 例如,下面的图书馆 实现关键字 例子的关键字 和 第二个 例子 。 没有 __all__
,它还将实现关键词 不公开为关键字 和 当前线程 。 最 重要的使用情况 __all__
是确保进口的助手 方法,如 current_thread
在下面的示例中,不是 意外暴露为关键词。
from threading import current_thread
__all__ = ['example_keyword', 'second_example']
def example_keyword():
if current_thread().name == 'MainThread':
print 'Running in main thread'
def second_example():
pass
def not_exposed_as_keyword():
pass
关键字的名字
关键字名称中使用的测试数据与方法名称 找到方法实现这些关键字。 名字比较 不区分大小写,空间和强调将被忽略。 为 的例子中,方法 你好
映射到关键字的名字 你好 , 你好 甚至h e l l o 。 同样的 do_nothing
和 doNothing
方法可以用作 什么都不做 关键字的测试数据。
例如Python库作为一个模块的实现 MyLibrary.py 文件:
def hello(name):
print "Hello, %s!" % name
def do_nothing():
pass
示例Java库实现为一个类 MyLibrary.java 文件:
public class MyLibrary {
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
public void doNothing() {
}
}
下面的例子说明了上面的示例库可以的 使用。 如果你想试试这个自己,确保图书馆 在 模块搜索路径 。
*** Settings ***
Library MyLibrary
*** Test Cases ***
My Test
Do Nothing
Hello world
使用自定义关键字的名字
可以公开为关键字,而不是一个不同的名称 默认关键字名称映射到方法的名称。 可以实现这 通过设置 robot_name
属性的方法所需的自定义名称。 装饰 robot.api.deco.keyword
可以使用一个设置的快捷方式吗 使用时,这个属性如下:
from robot.api.deco import keyword
@keyword('Login Via User Panel')
def login(username, password):
# ...
*** Test Cases ***
My Test
Login Via User Panel ${username} ${password}
使用这个修饰符没有争吵没有影响暴露 关键字的名字,但仍将创建 robot_name
属性。 这可能是有用的 为 标记方法公开为关键词 不改变 关键字的名字。
设置一个自定义关键字名称还可以启用库关键字接受 参数使用 嵌入参数 语法。
关键字参数
有一个静态和混合API,多少参数信息 关键字需要的是直接从方法实现它。 库的使用 动态库的API 有其他方式来分享吗 这个信息,所以这部分是不相关的。
最常见的,也是最简单的情况是当一个字需要一个 确切的数量的参数。 在这种情况下,Python和Java方法 简单地把这些参数。 例如,一个实现方法 关键字不带参数不需要参数,方法 用一个参数实现关键字也接受一个参数,即和 等等。
Python示例关键词在不同数量的参数:
def no_arguments():
print "Keyword got no arguments."
def one_argument(arg):
print "Keyword got one argument '%s'." % arg
def three_arguments(a1, a2, a3):
print "Keyword got three arguments '%s', '%s' and '%s'." % (a1, a2, a3)
请注意
Java库的一个主要限制使用静态库API 他们不支持吗 命名参数的语法 。 如果这 是一个拦截器,可以使用Python或者切换到吗 的 动态库的API 。
默认值为关键字
通常很有用的关键字使用的参数 默认值。 Python和Java有不同的语法处理违约 值方法,这些语言的自然语法 在创建测试库用于机器人框架。
默认值与Python
在Python中总是一个方法和可能的实现 在方法签名中指定默认值。 语法, 熟悉所有Python程序员,说明如下:
def one_default(arg='default'):
print "Argument has value %s" % arg
def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
print "Got arguments %s, %s and %s" % (arg1, arg2, arg3)
可以使用上面的第一个例子的关键字与0或1 参数。 如果没有给出参数, 参数
得到的值 默认的
。 如果有一个参数, 参数
这个值, 和调用关键字与多个参数失败。 在 第二个例子,一个参数永远是必需的,但第二和 第三个有默认值,因此可以使用关键字 有1至3个参数。
*** Test Cases ***
Defaults
One Default
One Default argument
Multiple Defaults required arg
Multiple Defaults required arg optional
Multiple Defaults required arg optional 1 optional 2
默认值与Java
在Java中一个方法可以有几个不同的实现 签名。 机器人框架将所有这些实现 关键字,可以使用不同的参数。 这个语法 因此被用来支持默认值。 这是 下面的例子所示,功能相同 早期的Python示例:
public void oneDefault(String arg) {
System.out.println("Argument has value " + arg);
}
public void oneDefault() {
oneDefault("default");
}
public void multipleDefaults(String arg1, String arg2, String arg3) {
System.out.println("Got arguments " + arg1 + ", " + arg2 + " and " + arg3);
}
public void multipleDefaults(String arg1, String arg2) {
multipleDefaults(arg1, arg2, "default 2");
}
public void multipleDefaults(String arg1) {
multipleDefaults(arg1, "default 1");
}
数量可变的参数( *可变参数
)
机器人框架支持关键字,把任意数量的 参数。 同样与默认值,实际的语法使用 在测试库在Python和Java是不同的。
与Python变量数量的参数
Python支持方法接受任意数量的参数。 相同的 语法在库和工作,正如下面的例子所显示的,它也可以 结合其他的方式指定参数:
def any_arguments(*args):
print "Got arguments:"
for arg in args:
print arg
def one_required(required, *others):
print "Required: %s\nOthers:" % required
for arg in others:
print arg
def also_defaults(req, def1="default 1", def2="default 2", *rest):
print req, def1, def2, rest
*** Test Cases ***
Varargs
Any Arguments
Any Arguments argument
Any Arguments arg 1 arg 2 arg 3 arg 4 arg 5
One Required required arg
One Required required arg another arg yet another
Also Defaults required
Also Defaults required these two have defaults
Also Defaults 1 2 3 4 5 6
与Java变量数目的参数
机器人框架支持 Java varargs语法 定义变量的数量 参数。 例如,以下两个关键字在功能上是相同的 上述Python示例相同的名称:
public void anyArguments(String... varargs) {
System.out.println("Got arguments:");
for (String arg: varargs) {
System.out.println(arg);
}
}
public void oneRequired(String required, String... others) {
System.out.println("Required: " + required + "\nOthers:");
for (String arg: others) {
System.out.println(arg);
}
}
还可以使用可变数量的参数也 有一个数组,或者从2.8.3机器人框架, 并不知道
最后一个参数或第二 如果 免费的关键字参数(* * kwargs) 使用。 这是说明 通过下面的例子,它在功能上是相同的 之前的:
public void anyArguments(String[] varargs) {
System.out.println("Got arguments:");
for (String arg: varargs) {
System.out.println(arg);
}
}
public void oneRequired(String required, List<String> others) {
System.out.println("Required: " + required + "\nOthers:");
for (String arg: others) {
System.out.println(arg);
}
}
请注意
只有 并不知道
是支持可变参数,不是的吗 它的子类型。
支持变量数量的参数有一个与Java关键字 限制:它只能当方法有一个签名。 因此它不是 可能有Java关键字与默认值和可变参数。 除此之外,只有机器人Framework 2.8和更新支持使用 varargs和 库的构造函数 。
免费的关键字参数( * * kwargs
)
机器人框架2.8添加了支持免费使用Python的关键字参数 * * kwargs
语法。 如何使用测试数据讨论了语法吗 在 免费的关键字参数 下节 创建测试用例 。 在这个 节中,我们来看看如何使用自定义测试库。
与Python免费的关键字参数
如果您已经熟悉如何kwargs Python,理解 他们使用机器人框架测试库很简单。 这个例子 显示了以下基本功能:
def example_keyword(**stuff):
for name, value in stuff.items():
print name, value
*** Test Cases ***
Keyword Arguments
Example Keyword hello=world # Logs 'hello world'.
Example Keyword foo=1 bar=42 # Logs 'foo 1' and 'bar 42'.
基本上,所有参数的关键字使用 命名参数的语法 名称=值
,任何不一致 其他参数,传递kwargs关键字。 避免使用文字 值如 foo = quux
作为一个免费的关键字参数,必须 逃了出来 就像foo \ = quux
。
下面的例子说明了如何正常的参数,varargs和kwargs 协同工作:
def various_args(arg, *varargs, **kwargs):
print 'arg:', arg
for value in varargs:
print 'vararg:', value
for name, value in sorted(kwargs.items()):
print 'kwarg:', name, value
*** Test Cases ***
Positional
Various Args hello world # Logs 'arg: hello' and 'vararg: world'.
Named
Various Args arg=value # Logs 'arg: value'.
Kwargs
Various Args a=1 b=2 c=3 # Logs 'kwarg: a 1', 'kwarg: b 2' and 'kwarg: c 3'.
Various Args c=3 a=1 b=2 # Same as above. Order does not matter.
Positional and kwargs
Various Args 1 2 kw=3 # Logs 'arg: 1', 'vararg: 2' and 'kwarg: kw 3'.
Named and kwargs
Various Args arg=value hello=world # Logs 'arg: value' and 'kwarg: hello world'.
Various Args hello=world arg=value # Same as above. Order does not matter.
对于一个真实世界的例子使用签名在上面完全一样 的例子,请参阅 运行过程 和 开始关键字 关键字的 过程 图书馆。
自由与Java关键字参数
从机器人框架2.8.3,还免费的Java库支持 关键字参数的语法。 Java本身没有kwargs语法,但是关键词 可以有 java.util.Map
作为最后一个参数来指定它们 接受kwargs。
如果一个Java关键字接受kwargs,机器人框架会自动包装 所有的参数 名称=值
语法的关键字 成一个 地图
并将其传递给关键字。 例如,后 可以使用关键字就像前面的例子Python示例:
public void exampleKeyword(Map<String, String> stuff):
for (String key: stuff.keySet())
System.out.println(key + " " + stuff.get(key));
public void variousArgs(String arg, List<String> varargs, Map<String, Object> kwargs):
System.out.println("arg: " + arg);
for (String varg: varargs)
System.out.println("vararg: " + varg);
for (String key: kwargs.keySet())
System.out.println("kwarg: " + key + " " + kwargs.get(key));
请注意
kwargs参数的类型必须完全 java.util.Map
, 没有它的子类型。
请注意
类似与 可变参数支持 关键字,支持 kwargs不能有一个以上的签名。
参数类型
通常关键字参数来机器人框架作为字符串。 如果 关键字需要一些其他类型,可以使用 变量 或将字符串转换成所需的类型关键字。 与 Java关键字 基本类型也自动强迫。
参数类型与Python
因为参数在Python中没有任何类型的信息, 不可能时自动将字符串转换为其他类型 使用Python库。 调用一个Python方法实现一个关键字 正确数量的参数总是成功,但执行 失败后,如果参数是不相容的。 幸运的是,Python 是简单的关键词:内参数转换为适当的类型
def connect_to_host(address, port=25):
port = int(port)
# ...
参数类型与Java
Java方法的参数类型,所有的基本类型 自动处理的。 这意味着参数是正常的 字符串的测试数据是正确的类型在运行时强制。 的 可以强迫类型:
- 整数类型(
字节
,短
,int
,长
) - 浮点类型(
浮动
和双
) - 的
布尔
类型 - 上述类型如的对象版本。
java.lang.Integer
强制完成的参数相同或兼容的 类型在所有关键字的签名方法。 在接下来的 例子中,关键字的转换是可以做到的 doubleArgument
和 compatibleTypes
,但不是 conflictingTypes
。
public void doubleArgument(double arg) {}
public void compatibleTypes(String arg1, Integer arg2) {}
public void compatibleTypes(String arg2, Integer arg2, Boolean arg3) {}
public void conflictingTypes(String arg1, int arg2) {}
public void conflictingTypes(int arg1, String arg2) {}
强制使用数值类型如果测试数据 字符串包含一个数字,和布尔类型必须的数据 包含字符串 真正的
或 假
。 强迫只是 如果原始测试数据值是一个字符串,但它是 当然还可以使用变量包含正确的类型 这些关键字。 使用变量是唯一的选择,如果关键词 冲突的签名。
*** Test Cases ***
Coercion
Double Argument 3.14
Double Argument 2e16
Compatible Types Hello, world! 1234
Compatible Types Hi again! -10 true
No Coercion
Double Argument ${3.14}
Conflicting Types 1 ${2} # must use variables
Conflicting Types ${1} 2
从机器人Framework 2.8,参数类型强制也有工作 Java库的构造函数 。
使用修饰符
当写静态的关键词,它有时候是有用和修改它们 Python的修饰符。 然而,decorator修改函数签名, 并且可以混淆机器人当确定哪些框架的自省 接受参数关键字。 这是在创建尤其成问题 库文件与 Libdoc 当使用 骑 。 为了避免这种情况 问题,或不使用修饰符,使用方便 decorator模块 创建signature-preserving修饰符。
将参数嵌入到关键字的名字
图书馆使用关键字也可以接受参数的传递 嵌入参数语法 。 的 robot.api.deco.keyword
装饰 可以用来创建一个 自定义关键字的名字 为关键字 包括所需的语法。
from robot.api.deco import keyword
@keyword('Add ${quantity:\d+} Copies Of ${item} To Cart')
def add_copies_to_cart(quantity, item):
# ...
*** Test Cases ***
My Test
Add 7 Copies Of Coffee To Cart
与机器人交流框架
后一种方法实现一个关键字,它可以使用任何 与被测系统通信机制。 它还可以 将消息发送到机器人框架的日志文件,返回的信息 可以保存到变量,最重要的是,报告如果 关键字了。
报告关键字状态
报告关键字状态进行简单地使用异常。 如果一个执行 方法提出了一个异常状态的关键字 失败
,如果它 返回正常,状态 通过
。
所示的错误消息日志,创建报告和控制台 从异常类型和它的消息。 (与通用的异常 的例子, AssertionError
, 异常
, RuntimeError
),只使用异常消息, 中创建的消息格式 ExceptionType: 实际消息
。
从机器人2.8.2框架,可以避免添加 异常类型的前缀失败消息也非一般的例外。 这是通过添加一个特殊的 ROBOT_SUPPRESS_NAME
属性与 价值 真正的
对你例外。
Python:
class MyError(RuntimeError):
ROBOT_SUPPRESS_NAME = True
Java:
public class MyError extends RuntimeException {
public static final boolean ROBOT_SUPPRESS_NAME = true;
}
在所有情况下,重要的是用户,异常消息 尽可能的丰富。
HTML错误消息
从机器人Framework 2.8开始,也有可能有HTML格式 错误消息从消息文本 * HTML *
:
raise AssertionError("*HTML* <a href='robotframework.org'>Robot Framework</a> rulez!!")
可以使用此方法既提高异常在图书馆时, 在上面的示例中,和 当用户在测试数据提供一个错误消息 。
自动切割长消息
如果超过40行错误消息,它将自动 从中间切防止报告太长 难以阅读。 完整的错误消息总是显示在日志中 消息失败的关键字。
回溯
异常的回溯也是登录使用 调试
日志级别 。 这些信息在日志文件默认情况下是不可见的,因为他们非常 很少有趣的普通用户。 在开发库,它通常是一个 好主意来运行测试 ——loglevel调试
。
停止测试执行
是有可能失败的测试用例,这样 整个测试执行 停止 。 只需有一个特别的 ROBOT_EXIT_ON_FAILURE
属性与 真正的
从关键字值集的异常。 在下面的例子中对此进行了阐述。
Python:
class MyFatalError(RuntimeError):
ROBOT_EXIT_ON_FAILURE = True
Java:
public class MyFatalError extends RuntimeException {
public static final boolean ROBOT_EXIT_ON_FAILURE = true;
}
继续测试执行,尽管失败
是有可能的 继续测试执行即使有故障 。 信号从测试库的方法是添加一个特殊的 ROBOT_CONTINUE_ON_FAILURE
属性与 真正的
值的异常 用来交流的失败。 这是证明了下面的例子。
Python:
class MyContinuableError(RuntimeError):
ROBOT_CONTINUE_ON_FAILURE = True
Java:
public class MyContinuableError extends RuntimeException {
public static final boolean ROBOT_CONTINUE_ON_FAILURE = true;
}
日志信息
异常消息不提供信息的唯一方法 用户。 除了他们之外,还可以发送消息的方法 日志 文件 只要写入标准输出(stdout)或流 标准错误流(stderr),他们甚至可以使用不同的 日志级别。 另一个,往往更好,日志可能是使用 的 程序化的日志记录api 。
默认情况下,所有写的方法到标准输出 写入日志文件作为一个单独的条目的日志级别 信息
。 消息写入标准错误处理 同样否则,但是他们回到原来的stderr回荡 关键字后执行完成。 它就可以使用 stderr如果你需要一些消息显示在控制台的地方 测试执行。
使用日志级别
使用其他日志级别 信息
,或者创建几个 消息,显式地指定的日志级别通过嵌入水平 消息的格式 *级*实际的日志消息
,在那里 *级*
必须在一行的开头吗 水平
是 一个可用的日志级别 跟踪
, 调试
, 信息
, 警告
, 错误
和 HTML
。
错误和警告
消息 错误
或 警告
会自动写入 控制台和一个单独的 测试执行错误部分 在日志中 文件。 这使得这些消息比其他人更明显,并允许 使用它们重要但非关键问题报告给用户。
请注意
在机器人Framework 2.9,新功能添加到自动 将错误记录通过关键词添加到测试执行错误部分。
日志的HTML
一切正常登录到图书馆将被转换成一个 格式,可以安全地表示为HTML。 例如, < b > foo < / b >
将显示在日志到底这样 不像 喷火 。 如果图书馆想使用格式化、链接、显示 图片等等,他们可以使用一个特殊的伪日志级别 HTML
。 机器人框架将这些信息直接写入 的日志 信息
水平,所以他们可以使用任何HTML语法 他们想要的东西。 请注意,此功能需要小心使用, 因为,例如,一个严重 < /表>
标签可以毁了 日志文件相当严重。
当使用 公共日志API ,各种测井方法 有可选的 html
可以设置属性 真正的
启用登录HTML格式。
时间戳
默认消息记录通过标准输出或错误流 执行关键字结束的时候得到他们的时间戳。 这意味着 时间戳是不准确的,尤其是在调试问题 长期运行的关键字可以有问题。
关键字有可能将一个精确的时间戳添加到消息 如果有必要他们日志。 必须给出毫秒的时间戳 自 Unix新纪元 它必须放在后 日志级别 用冒号分开:
*INFO:1308435758660* Message with timestamp *HTML:1308435758661* <b>HTML</b> message with timestamp
如下面的例子所示,添加时间戳是容易的 使用Python和Java。 如果你是使用Python,,然而, 使用的更容易获得准确的时间戳 程序化的日志 api 。 显式地添加时间戳的一大好处是,这 方法也与工作 远程库接口 。
Python:
import time
def example_keyword():
print '*INFO:%d* Message with timestamp' % (time.time()*1000)
Java:
public void exampleKeyword() {
System.out.println("*INFO:" + System.currentTimeMillis() + "* Message with timestamp");
}
日志记录到控制台
如果库需要写点东西给他们有几个的控制台 选项。 正如已经讨论的,警告和写入所有消息 标准错误流都写日志文件和 控制台。 这两个选项有一个限制,结束的消息 后控制台仅当前执行的关键字 完成。 奖金是这些方法与Python和两个工作 基于Java库。
另一个选择,那就是只能用Python写 消息 sys.__stdout__
或 sys.__stderr__
。 当 使用这种方法,消息立即写入控制台 而不是写入日志文件:
import sys
def my_keyword(arg):
sys.__stdout__.write('Got arg %s\n' % arg)
最后的选择是使用 公共日志API :
from robot.api import logger
def log_to_console(arg):
logger.console('Got arg %s' % arg)
def log_to_console_and_log_file(arg)
logger.info('Got arg %s' % arg, also_console=True)
日志的例子
在大多数情况下, 信息
水平是足够的。 下面的水平, 调试
和 跟踪
写作,是有用的调试信息。 这些消息通常没有显示,但他们可以方便调试 可能出现的问题在图书馆本身。 的 警告
或错误
水平可以 被用来制造更多的可见光和消息 HTML
是有用的,如果任何 的格式是必要的。
下面的例子说明如何使用不同的日志级别 的工作原理。 Java程序员应该把代码 打印“消息”
作为伪代码的含义 System.out.println(“信息”);
。
print 'Hello from a library.'
print '*WARN* Warning from a library.'
print '*ERROR* Something unexpected happen that may indicate a problem in the test.'
print '*INFO* Hello again!'
print 'This will be part of the previous message.'
print '*INFO* This is a new message.'
print '*INFO* This is <b>normal text</b>.'
print '*HTML* This is <b>bold</b>.'
print '*HTML* <a href="http://robotframework.org">Robot Framework</a>'
程序化的日志记录api
编程api提供一些日志信息比清洁方法 使用标准输出和错误流。 目前,这些 接口只提供给Python基地测试库。
公共日志API
机器人框架基于Python的写作日志API 消息日志文件和控制台。 测试库可以使用 这个API一样 logger.info(“我的信息”)
相反的日志 通过标准输出 打印“*信息*我的消息”
。 在 除了一个编程接口被很多清洁使用, API的一个好处,日志消息准确 时间戳 。
公共日志API 是彻底的记录 作为API的一部分 文档在 https://robot-framework.readthedocs.org 。 下面是 一个简单的使用例子:
from robot.api import logger
def my_keyword(arg):
logger.debug('Got argument %s' % arg)
do_something()
logger.info('<i>This</i> is a boring example', html=True)
logger.console('Hello, console!')
一个明显的限制是测试库使用这个日志API 一个依赖机器人框架。 之前版本2.8.7机器人也有 运行日志记录的工作。 从机器人2.8.7框架 如果机器人不运行消息被自动重定向到Python的 标准 日志记录 模块。
使用Python的标准 日志记录
模块
除了新的 公共日志API ,机器人提供了一个框架 Python的标准的内置支持 日志记录 模块。 这 工作,使所有接收到的消息的根记录器 模块会自动传播到机器人框架的日志 文件。 也该API生成日志消息准确 时间戳 , 但是日志HTML消息或写消息到控制台 支持。 一个大好处,也显露了简单的例子 下面是使用这个日志API创建并不依赖于机器人 框架。
import logging
def my_keyword(arg):
logging.debug('Got argument %s' % arg)
do_something()
logging.info('This is a boring example')
的 日志记录
模块有稍微不同的日志级别 机器人框架。 它的水平 调试
, 信息
, 警告
和 错误
被映射 直接匹配的机器人框架日志级别, 至关重要的
映射到 错误
。 自定义日志级别映射到最接近 标准级别小于自定义级别。 例如,一个水平 之间的 信息
和 警告
映射到机器人框架的 信息
的水平。
记录在库初始化
图书馆也可以记录在测试期间图书馆导入和初始化。 这些信息不会出现在 日志文件 像正常的日志消息, 而是写入 syslog 。 这允许任何类型的日志记录 有用的调试信息的库初始化。 消息记录 使用 警告
或 错误
水平也是可见的 测试执行错误 部分在日志文件中。
日志在导入和使用初始化是可能的 标准输出和错误流 和 程序化的日志记录api 。 下面演示了这两种。
通过在初始化期间stdout Java库的日志:
public class LoggingDuringInitialization {
public LoggingDuringInitialization() {
System.out.println("*INFO* Initializing library");
}
public void keyword() {
// ...
}
}
Python库日志使用日志API在导入:
from robot.api import logger
logger.debug("Importing library")
def keyword():
# ...
请注意
如果你日志在初始化期间,即在Python中 __init__
或在Java构造函数中,可能的消息 根据多次登录 测试库范围 。
返回值
最后为关键词回到核心框架通信 返回信息从被测系统或检索 由一些其他手段。 返回的值可以 分配给 变量 在测试数据作为输入,然后用于其他关键词, 甚至在不同的测试库。
返回值使用 返回
声明从 Python和Java方法。 通常,一个值被分配到一个 标量变量 ,如以下示例所示。 这个例子 也说明了可以返回任何对象和使用 扩展变量语法 访问对象属性。
from mymodule import MyObject
def return_string():
return "Hello, world!"
def return_object(name):
return MyObject(name)
*** Test Cases ***
Returning one value
${string} = Return String
Should Be Equal ${string} Hello, world!
${object} = Return Object Robot
Should Be Equal ${object.name} Robot
关键字也可以返回值,这样就可以分配 几个 标量变量 在一次, 变量列表 ,或 标量变量,变量列表。 所有这些用法需要 Python列表或元组或返回值 在Java数组,列表,或者迭代器。
def return_two_values():
return 'first value', 'second value'
def return_multiple_values():
return ['a', 'list', 'of', 'strings']
*** Test Cases ***
Returning multiple values
${var1} ${var2} = Return Two Values
Should Be Equal ${var1} first value
Should Be Equal ${var2} second value
@{list} = Return Two Values
Should Be Equal @{list}[0] first value
Should Be Equal @{list}[1] second value
${s1} ${s2} @{li} = Return Multiple Values
Should Be Equal ${s1} ${s2} a list
Should Be Equal @{li}[0] @{li}[1] of strings
当使用线程通信
如果图书馆使用线程时,它通常与沟通 仅从主线程框架。 如果一个工作线程, 例子中,未能报告或记录的东西,它应该通过 第一个主线程的信息,可以使用异常或 其他机制在这一节中沟通的解释 框架。
当线程运行在后台,这尤其重要 其他关键字正在运行。 沟通的结果 框架在这种情况下是未定义的,在最坏的情况下会导致 崩溃或损坏输出文件。 如果一个关键字开始的东西 背景,应该有另一个关键字,检查的状态 工作线程和报告收集相应的信息。
消息记录由非主要线程使用正常的测井方法 程序化的日志记录api 是默默地忽略。
还有一个 BackgroundLogger
在单独的 robotbackgroundlogger 项目, 与类似的API标准 robot.api.logger
。 正常的日志 方法将忽略消息从主线程之外,但是 BackgroundLogger
将节省的背景信息,这样他们以后可以吗 机器人的日志记录。
分发测试库
记录库
一个测试库没有文档什么关键词 包含这些关键词做相当无用。 为了缓解 维护,强烈建议库文档 包含在源代码和生成。 基本上,这 意味着使用 文档字符串 与Python和 Javadoc 与Java 下面的例子。
class MyLibrary:
"""This is an example library with some documentation."""
def keyword_with_short_documentation(self, argument):
"""This keyword has only a short documentation"""
pass
def keyword_with_longer_documentation(self):
"""First line of the documentation is here.
Longer documentation continues here and it can contain
multiple lines or paragraphs.
"""
pass
/**
* This is an example library with some documentation.
*/
public class MyLibrary {
/**
* This keyword has only a short documentation
*/
public void keywordWithShortDocumentation(String argument) {
}
/**
* First line of the documentation is here.
*
* Longer documentation continues here and it can contain
* multiple lines or paragraphs.
*/
public void keywordWithLongerDocumentation() {
}
}
Python和Java工具创建的API文档 库记录。 然而,这些工具可以稍微的输出 技术对一些用户。 另一个替代方法是使用机器人 框架的文档工具 Libdoc 。 这个工具可以 创建一个库文档从Python和Java库 使用静态库API,比如上面的,但它还处理 库的使用 动态库的API 和 复合图书馆的API 。
第一行是用于特殊关键字的文档 目的和应该包含一个简短的总体的描述 关键字。 它被用作 简短的文档 举例来说,作为一种工具 提示, Libdoc 并显示在测试日志中。 然而,后者 不使用Java库使用静态API, 因为他们的文件是迷失在编译和不可用 在运行时。
默认文档被认为是遵循框架的机器人 文档格式 规则。 这个简单的格式允许经常使用 风格像 *大胆的*
和 _italic_
、表、列表、链接等。 2.7.5从机器人框架,它还可以使用HTML,平原 文本和 reStructuredText 格式。 看到 指定文档格式 部分信息如何设置库中的源代码和格式 Libdoc 章关于格式的更多信息。
请注意
如果您想要使用非ascii字符的文档 Python库,您必须使用utf - 8作为你的 源代码 编码 或创建文档字符串是Unicode。
测试库
任何有价值的图书馆需要全面测试,防止测试 bug。 当然,这个测试应该自动化 当库改变容易重新运行测试。
Python和Java都有优秀的单元测试工具,并且他们套件 很好测试库。 不存在重大的差异 使用它们为此目的而使用一些其他的 测试。 熟悉这些工具的开发人员不需要学习 新的东西,开发人员不熟悉他们应该学习 他们无论如何。
它也很容易使用机器人框架本身进行测试库 这样对他们有实际的端到端验收测试。 有 大量的有用的关键词 内装式 图书馆对这 目的。 特别值得一提的是 运行关键字和期望 错误 ,这是有用的关键词报告错误的测试 正确。
是否使用一个单位或验收标准测试方法取决于 上下文。 如果有需要模拟实际系统 测试中,通常更容易在单元级别。 另一方面, 验收测试确保关键词做机器人 框架。 如果你不能决定,当然可以同时使用 的方法。
包装库
图书馆实现后,记录,和测试,它仍然需要 分发给用户。 简单的图书馆组成的 单一的文件时,它通常是足以让用户复制该文件 的地方,设置 模块搜索路径 相应的行动。 更多的 复杂的图书馆应该被打包安装 更容易。
由于库是正常的编程代码,他们可以打包 使用正常的包装工具。 与Python,选项包括好 distutils 、包含Python标准库的更新 setuptools 。 这些工具的一个好处是,库模块 安装到一个位置,是自动的 模块 搜索路径 。
当使用Java,它是自然包库塞在一个瓶子 档案。 JAR包必须放入 模块搜索路径 在运行测试之前,但它很容易创建一个 启动脚本 那 自动。
不以为然的关键词
有时需要用新的替换现有的关键词 或者干脆删除它们。 只是通知用户有关的改变 可能并不总是不够,这是更有效的警告 运行时。 支持,机器人框架有一个马克的能力 关键字 弃用。 这使它更容易找到旧的关键词 测试数据和删除或替换他们。
关键字可以被开始弃用他们的文档文本 *弃用
区分大小写,关闭 *
还在第一 的文档。 例如, *不*
, *,*
, 在1.5版。* *弃用
都是有效的标记。
当执行一个弃用关键字时,弃用警告记录 在显示的警告 控制台和测试执行错误 在日志文件 。 弃用警告从文本开始 关键字 <名称>的弃用。
剩下的 简短的文档 后 弃用标记(如果有的话)。 例如,如果以下 执行关键字时,会出现一个警告信息,就像下面所示的日志文件。
def example_keyword(argument):
"""*DEPRECATED!!* Use keyword `Other Keyword` instead.
This keyword does something to given ``argument`` and returns results.
"""
return do_something(argument)
弃用系统与大多数测试库和工作 用户的关键字 。 唯一的例外是关键字实现 使用Java测试库 静态库接口 因为 他们的文档在运行时不可用。 这样的关键字, 它可以使用用户关键词包装和轻视他们。
请注意
机器人框架2.9之前的文档必须开始 *不*
之前完全没有任何额外的内容 关闭 *
。
动态库API
动态API是在很多方面类似于静态API。 为 关键字状态报告,记录,并返回值 完全相同的方式工作。 最重要的是,没有差异 在进口相比,动态库和使用他们的关键词 其他库。 换句话说,用户不需要知道他们的api 图书馆使用。
只有静态和动态库之间的区别 机器人框架如何发现什么关键词库实现, 这些关键字参数和文档,以及如何 关键词是实际执行。 与静态API,这一切都是 通过使用反射(Java库的文件除外), 但是动态库用于这些有特殊的方法 目的。
动态API的好处之一是,你有更大的灵活性 组织你的图书馆。 有静态API,您必须拥有所有 关键字在一个类或模块,而动态API,你可以, 例如,实现每个关键字作为一个单独的类。 这个用例是 与Python不重要,不过,因为它的动态能力 多重已经给足够的灵活性,也有 可能使用 复合图书馆的API 。
另一个主要的用例动态API实现图书馆 所以它是代表可能运行在一个实际的图书馆 甚至一些其他进程或另一台机器上。 这样的一个代理 图书馆可以很薄,因为关键字名称和所有其他 信息动态,没有需要更新的代理 当新的关键字添加到实际的库。
本节解释之间的动态API是如何工作的机器人 框架和动态库。 无关紧要的机器人 框架这些库实际上是如何实现(例如, 如何调用 run_keyword
被映射到一个正确的方法 关键字实现),和许多不同的方法 可能的。 然而,如果您使用Java,您可能要检查 JavalibCore 之前实现自己的系统。 这组 可重用的工具支持多种方式创建关键字,它是 可能已经有一个机制,套房您的需求。
获取关键字的名字
动态库告诉他们关键字实现的 get_keyword_names
方法。 该方法也有别名 getKeywordNames
建议在使用Java。 这 方法不能采取任何参数,它必须返回一个列表或数组 字符串包含的名称关键词库中实现的。
如果返回的关键字名称包含几个词,它们可以返回 用空格或下划线分隔或camelCase格式。 为 的例子, (“第一关键字”、“二字”)
, (“first_keyword”、“second_keyword”)
,(“firstKeyword”、“secondKeyword”)
都被映射到关键字 第一个关键字 和 第二个字 。
动态库必须总是有这种方法。 如果它丢失,或 如果调用失败由于某种原因,图书馆被认为是 静态库。
标记方法公开为关键词
如果一个动态库应该包含两种方法是关键词 和方法是私人助手方法,这可能是明智的 马克关键词等方法更容易实现 get_keyword_names
。 的 robot.api.deco.keyword
装饰器允许一个简单的方法,因为它 创建一个自定义 robot_name
属性上的装饰方法。 这使得生成的关键词只通过检查列表 robot_name
属性在每个方法在图书馆 get_keyword_names
。 看到 使用自定义关键字的名字 更多关于这个修饰符。
from robot.api.deco import keyword
class DynamicExample:
def get_keyword_names(self):
return [name for name in dir(self) if hasattr(getattr(self, name), 'robot_name')]
def helper_method(self):
# ...
@keyword
def keyword_method(self):
# ...
运行关键字
有一个特殊的动态库 run_keyword
(别名 runKeyword
)方法执行他们的关键词。 当一个 关键字从一个动态库中使用的测试数据,机器人 框架使用图书馆的 run_keyword
方法得到它 执行。 这个方法取两个或三个参数。 第一个参数是一个 字符串包含关键字的名称相同的执行 返回的格式 get_keyword_names
。 第二个参数是 列表或数组的参数测试数据的关键字。
可选的第三个参数是一个字典(地图在Java) 可能的 免费的关键字参数 ( * * kwargs
)传递到 关键字。 看到 免费的关键字参数与动态库 部分 更多细节关于使用kwargs与动态测试库。
在得到关键字名称和参数,图书馆可以执行 关键字自由,但必须使用相同的机制 与框架为静态库。 这意味着使用 异常报告关键字状态、日志记录通过编写 提供的标准输出或使用日志api,并使用 的返回语句 run_keyword
对返回的东西。
每一个动态库必须有两个 get_keyword_names
和 run_keyword
但是其他的方法在动态方法 API是可选的。 下面的例子展示了一个工作,虽然 琐碎,在Python中实现动态库。
class DynamicExample:
def get_keyword_names(self):
return ['first keyword', 'second keyword']
def run_keyword(self, name, args):
print "Running keyword '%s' with arguments %s." % (name, args)
获取关键字参数
如果只实现了一个动态库 get_keyword_names
和 run_keyword
方法,机器人框架没有任何信息 关于实现的关键字需要的参数。 例如, 这两个 第一个关键字 和 第二个字 在上面的例子中 可以使用任意数量的参数。 这是有问题的, 因为大多数真正的关键词期望一定数量的关键字,和 在这种情况下,他们需要检查参数计数 他们自己。
动态库可以告诉机器人框架参数关键字 它实现了预期通过使用 get_keyword_arguments
(别名 getKeywordArguments
)方法。 这个方法取这个名字 的一个关键字作为参数,并返回一个列表或数组的字符串 包含关键字的参数接受。
同样作为静态关键词,动态关键字可以要求任何号码 参数的默认值,并接受变量的数量 参数和关键字参数。 如何表示的语法 所有这些不同的变量在下面的表格说明。 注意,列表的例子使用Python语法,但Java开发人员 应该使用Java字符串列表或数组。
预期 参数 | 如何表示 | 例子 | 限制 (最小/最大) |
---|---|---|---|
没有参数 | 空列表。 |
[] |
0/0
|
一个或多个 论点 | 字符串列表包含 参数名称。 |
(“one_argument”) (a1,a2,a3的) |
1/1
3/3
|
默认值 为参数 | 默认值分离 从名字 = 。 默认值总是 认为是字符串。 |
['arg=default value']
[a,b = 1,“c = 2”) |
0/1
1/3
|
变量的数量 的参数 (可变参数) | 最后(或第二 kwargs)参数 * 它的名字。 |
['*varargs']
['a', 'b=42', '*rest']
|
0 /任何
1 /任何
|
免费的关键字 参数(kwargs) | 最后一个参数 * * 它的名字。 |
['**kwargs']
[a,b = 42 ',' * * kws '] ['*varargs', '**kwargs']
|
0/0
1/2
0 /任何
|
当 get_keyword_arguments
使用,自动机器人框架吗 计算有多少位置参数关键字需要它 支持免费的关键字参数。 如果使用一个关键字无效 参数,发生错误 run_keyword
甚至没有。
实际参数名称和返回的默认值也 重要的。 他们需要 命名参数支持 和 Libdoc 工具需要能够创建一个有意义的库文件。
如果 get_keyword_arguments
缺失或返回 没有一个
或 零
对于一个特定的关键字,关键字被论证的规范 接受所有参数。 这种自动参数规范 [*可变参数,* * kwargs]
或 (*可变参数)
,根据run_keyword
支持kwargs 通过三个参数。
获取关键字的文档
最后的特殊方法,动态库可以实现 get_keyword_documentation
(别名 getKeywordDocumentation
)。 需要作为一个关键字的名字 参数,方法名称所暗示的,返回的文档 一个字符串。
返回的文档使用同样的关键字 与静态库实现文档字符串 Python。 主要的用例是关键字的文件到一个 库生成的文档 Libdoc 。 此外, 文档的第一行(直到第一 \ n
)是 测试日志中所示。
让通用库文档
的 get_keyword_documentation
方法也可以用来 指定总体库文档。 这个文档不是 测试执行时使用,但它可以使文档 生成的 Libdoc 好多了。
动态库可以提供文档和通用库 文档相关的图书馆投入使用。 前者是 通过调用了 get_keyword_documentation
具有特殊价值 __intro__
,后者是有使用价值 __init__
。 文档介绍如何最好的测试吗 与 Libdoc 在实践中。
基于Python的动态库还可以指定通用库 文档直接在代码的文档字符串库 类及其 __init__
方法。 如果一个非空的文档 收到的代码和直接 get_keyword_documentation
方法,后者优先。
命名参数语法与动态库
从机器人Framework 2.8,动态库API支持 的 命名参数的语法 。 使用语法的基础上工作 参数名称和默认值 从图书馆了 使用 get_keyword_arguments
方法。
大部分地区的命名参数语法与动态关键字 就像它的工作原理与其他关键字支持它。 唯一特别的 一个例子是一个关键字与默认有多个参数 后者的值,只有一些。 在这种情况下,框架 充满了可选参数基于返回的默认值 由 get_keyword_arguments
方法。
使用命名参数的语法与动态库 通过下面的例子。 所有的示例使用一个关键字 动态 被指定的参数规范 [__arg1、最长= xxx,长度= yyy]
。 评论显示关键字实际上是调用的参数。
*** Test Cases ***
Only positional
Dynamic a # [a]
Dynamic a b # [a, b]
Dynamic a b c # [a, b, c]
Named
Dynamic a arg2=b # [a, b]
Dynamic a b arg3=c # [a, b, c]
Dynamic a arg2=b arg3=c # [a, b, c]
Dynamic arg1=a arg2=b arg3=c # [a, b, c]
Fill skipped
Dynamic a arg3=c # [a, xxx, c]
免费的关键字参数与动态库
从机器人框架2.8.2,动态库也可以支持 免费的关键字参数 ( * * kwargs
)。 一个强制性的先决条件 是,这种支持 run_keyword
方法 有三个参数 : 第三个将kwargs时使用。 Kwargs传递到 关键字作为一个字典(Python)或地图(Java)。
参数关键字接受取决于什么 get_keyword_arguments
返回它 。 如果最后一个参数 * *
关键字是 确认接受kwargs。
使用免费的关键字参数的语法与动态库 通过下面的例子。 所有的示例使用一个关键字 动态 被指定的参数规范 [__arg1 = xxx)最长=多,* * kwargs]
。 评论显示关键字实际上是调用的参数。
*** Test Cases ***
No arguments
Dynamic # [], {}
Only positional
Dynamic a # [a], {}
Dynamic a b # [a, b], {}
Only kwargs
Dynamic a=1 # [], {a: 1}
Dynamic a=1 b=2 c=3 # [], {a: 1, b: 2, c: 3}
Positional and kwargs
Dynamic a b=2 # [a], {b: 2}
Dynamic a b=2 c=3 # [a], {b: 2, c: 3}
Named and kwargs
Dynamic arg1=a b=2 # [a], {b: 2}
Dynamic arg2=a b=2 c=3 # [xxx, a], {b: 2, c: 3}
总结
所有特殊方法在动态API的表中列出 在下面。 方法名称列出下划线格式,但是他们的 camelCase别名完全相同的方式工作。
的名字 | 参数 | 目的 |
---|---|---|
get_keyword_names |
返回名称 的关键字来实现。 | |
run_keyword |
名称,参数,kwargs |
执行指定的关键字 用给定的参数。 kwargs 是可选的。 |
get_keyword_arguments |
的名字 |
返回关键字” 参数规格 。 可选的方法。 |
get_keyword_documentation |
的名字 |
返回关键字和图书馆的 文档 。 可选的方法。 |
可以用Java写一个正式的接口规范 在下面。 然而,请记住,库 不需要 来实现 任何显式接口,因为机器人框架直接检查 如果图书馆具有所需的反射 get_keyword_names
和 run_keyword
方法或其camelCase别名。 此外, get_keyword_arguments
和 get_keyword_documentation
是完全可选的。
public interface RobotFrameworkDynamicAPI {
List<String> getKeywordNames();
Object runKeyword(String name, List arguments);
Object runKeyword(String name, List arguments, Map kwargs);
List<String> getKeywordArguments(String name);
String getKeywordDocumentation(String name);
}
请注意
除了使用 列表
,它还可以使用数组 就像 对象[]
或 String[]
。
使用动态API的一个很好的例子是机器人的框架 远程库 。
复合library API
复合图书馆的API,顾名思义,之间的混合 静态API和动态API。 就像动态API,它是 可能实现图书馆使用混合API类。
获取关键字的名字
关键字的名字是在动态的完全一样 API。 在实践中,图书馆需要 get_keyword_names
或 getKeywordNames
方法返回 图书馆实现的关键字名称的列表。
运行关键字
在混合API,没有 run_keyword
方法执行 关键词。 相反,机器人框架使用反射来发现方法 实现关键字,同样与静态API。 一个图书馆 使用混合API可以实现这些方法 直接或,更重要的是,它可以动态地处理它们。
在Python中,很容易处理丢失的动态方法 __getattr__
方法。 这种特殊的方法可能是熟悉的 大多数Python程序员,他们可以立即理解 下面的例子。 其他人可能会发现更容易参考Python的参考 手册 第一。
from somewhere import external_keyword
class HybridExample:
def get_keyword_names(self):
return ['my_keyword', 'external_keyword']
def my_keyword(self, arg):
print "My Keyword called with '%s'" % arg
def __getattr__(self, name):
if name == 'external_keyword':
return external_keyword
raise AttributeError("Non-existing attribute '%s'" % name)
请注意, __getattr__
不执行实际的关键字 run_keyword
动态API。 相反,它只 返回一个可调用对象,然后执行的机器人框架。
注意的另一点是机器人框架使用相同的名称 是回来 get_keyword_names
寻找方法 实现它们。 因此实现的方法的名称 类本身必须返回相同的格式 定义的。 例如,上面的库不会正常工作,如果 get_keyword_names
返回 我的关键字
而不是 my_keyword
。
混合使用Java API不是很有用,因为它不是 可能处理缺失的方法。 当然,这是可能的 实现类中的所有方法库,但这带来了一些 好处相比静态API。
关键字参数和文档
当使用这个API时,机器人框架使用反射来发现 方法实现关键词,同样与静态API。 后 得到一个参考方法,它对参数和搜索 文档,使用静态时相同的方式 API。 因此不需要特殊的方法得到参数 和文档如有动态API。
总结
当执行一个测试库在Python中,混合API相同 动态能力的实际动态API。 是一个伟大的好处 没有需要特殊的方法获取关键字 参数和文档。 它也经常实用,唯一的真实 动态关键字需要处理 __getattr__
和其他人 可以直接在主库类来实现。
由于明显的好处和同等能力,混合API 在大多数情况下是一个更好的选择比动态API在使用吗 Python。 一个值得注意的例外是实现图书馆作为一个代理 一个实际的库实现在其他地方,因为实际 关键字必须执行其他地方,代理只能向前传递 关键字名称和参数。
使用混合API的一个很好的例子是机器人的框架 远程登录 图书馆。
使用机器人框架的内部模块
测试库使用Python实现可以使用机器人框架的 内部模块,例如,要获取的信息执行 测试和使用的设置。 这个强大的机制 与框架应小心使用,不过, 因为所有机器人框架的api并不意味着使用 不同框架之间的外部,他们可能会彻底改变 版本。
可用的api
从机器人Framework 2.7开始, API文档 分别举办 在优秀的 阅读文档 服务。 如果你不确定如何使用 某些API或使用它们向前兼容,请发送一个问题 来 邮件列表 。
使用内建库
最安全的API来实现关键字的使用方法 内装式 图书馆。 关键词是罕见的,他们总是变化 这样做,老使用第一个弃用。 一个最有用的 方法 replace_variables
它允许访问目前 可用的变量。 下面的例子演示了如何获得 $ { OUTPUT_DIR }
这是许多方便吗 自动 变量 。 还可以设置新的变量从库 使用 set_test_variable
, set_suite_variable
和 set_global_variable
。
import os.path
from robot.libraries.BuiltIn import BuiltIn
def do_something(argument):
output = do_something_that_creates_a_lot_of_output(argument)
outputdir = BuiltIn().replace_variables('${OUTPUTDIR}')
path = os.path.join(outputdir, 'results.txt')
f = open(path, 'w')
f.write(output)
f.close()
print '*HTML* Output written to <a href="results.txt">results.txt</a>'
唯一美中不足的使用方法 内装式
是所有 run_keyword
方法变异必须特别处理。 方法使用 run_keyword
方法必须注册 作为 运行关键字 自己使用 register_run_keyword
方法 内装式
模块。 这种方法的文档解释道 为什么需要这样做,显然还怎么做。
扩展现有测试库
本节解释不同的方法如何添加新的 功能对现有测试库和如何使用它们 否则自己的库。
修改原始源代码
如果你有访问库的源代码 自然扩展,你可以直接修改源代码。 最大的 这种方法的问题是,很难给你更新 原来的图书馆在不影响您的更改。 用户也可以 被混淆使用图书馆,有不同的功能 最初的一个。 也可能是一个额外的重新包装图书馆 的任务。
这种方法是通用的,非常好用,如果增强 你打算报回到最初的开发人员。 如果你的 更改应用到原始库,它们包含在 未来版本和上面讨论的所有问题是减轻。 如果 变化非泛型,或者因为其他原因不能提交 回来,在后续部分中解释的方法 可能做得更好。
使用继承
另一个简单的方法来扩展现有的图书馆使用 继承。 下面的示例所示,添加新的 标题应该与 关键字的 SeleniumLibrary 。 这 示例使用Python,但你可以明显延长现有的Java 图书馆在Java代码中相同的方式。
from SeleniumLibrary import SeleniumLibrary
class ExtendedSeleniumLibrary(SeleniumLibrary):
def title_should_start_with(self, expected):
title = self.get_title()
if not title.startswith(expected):
raise AssertionError("Title '%s' did not start with '%s'"
% (title, expected))
这种方法很大的差异而修改原始 图书馆是新图书馆比有一个不同的名称 原创。 一个好处是,你可以很容易地告诉你使用 自定义库,但是一个大问题是,你不能轻易使用 与原有的新图书馆。 首先你的新图书馆 关键字一样总是存在的原始意义 冲突 。 另一个问题是,图书馆不分享他们 状态。
这种方法适用当你开始使用新图书馆和想要的 从一开始添加自定义增强它。 否则其他 本节解释说可能是更好的机制。
直接使用其他库
因为技术测试库类或模块 简单的方法使用另一个图书馆是进口和使用它 方法。 这种方法可以很好方法是静态的,做的时候 不依赖于库的状态。 这是前面所示 例如,使用 机器人框架的内装式图书馆 。
如果库状态,然而,事情可能不像你会工作 希望。 图书馆实例你在图书馆将不会被使用 一样的框架使用,从而改变通过执行关键字 你的图书馆是不可见的。 下一节将解释如何 一个访问相同的库实例框架使用。
从机器人获得活动库实例的框架
内装式 关键字 获得图书馆实例 可以得到吗 当前活动实例库框架本身。 的 图书馆实例返回的这个关键字是一样的框架 本身使用,因此没有问题看到正确的库 状态。 虽然这个功能可以作为关键字,它是 通常用在测试库直接导入 内装式 库类 正如前面所讨论的 。 下面的例子说明了 如何实现相同的 标题应该与 关键字在 前面的例子 使用继承 。
from robot.libraries.BuiltIn import BuiltIn
def title_should_start_with(expected):
seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
title = seleniumlib.get_title()
if not title.startswith(expected):
raise AssertionError("Title '%s' did not start with '%s'"
% (title, expected))
这种方法显然比直接导入库 和使用图书馆的时候有一个状态。 最大的好处 继承是,您可以使用原来的图书馆通常和使用 新图书馆除了它在需要的时候。 这是在 下面的例子在前面的例子的代码 预计将在一个新的图书馆 SeLibExtensions 。
*** Settings ***
Library SeleniumLibrary
Library SeLibExtensions
*** Test Cases ***
Example
Open Browser http://example # SeleniumLibrary
Title Should Start With Example # SeLibExtensions
使用动态库或混合API
测试使用的库 动态 或 复合图书馆的API 经常 有自己的系统如何扩展它们。 使用这些库 从图书馆需要问指导开发人员或咨询 库文件或源代码。