创建测试库
支持的编程语言
模块。
外部运行,另一个广泛使用的方法 脚本或工具作为单独的进程。
提示
覆盖足够的Python语言开始编写测试 图书馆使用它。 它还包含一个简单的示例库 和测试用例,您可以执行,否则调查 在您的机器上。
不同的测试库api
机器人框架有三个不同的测试库api。
静态API
声明。
动态API
动态库的类实现方法的名字 他们实现的关键字,另一个方法来执行一个命名 关键字与给定的参数。 的名称关键字来实现,如 以及他们是如何执行,可以动态地确定 运行时,但报告状态、日志记录和返回值 同样是在静态API。
混合API
这是一个静态和动态API之间的混合。 图书馆是 类方法告诉他们关键字实现,但是 这些关键字必须直接可用。 一切除了 发现关键字实现的相似 静态API。
不同于它 然后自己的章节中讨论。
在本章的例子主要是使用Python,但他们 为纯java开发人员也应该很容易理解。 在那些 一些api有分歧的情况下,两种用法都解释 足够的例子。
创建测试库类或模块
测试库可以作为Python模块和Python或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 ...
}
}
}
测试库范围
图书馆实现类可以有一个内部状态,可以 被改变通过关键词和参数的构造函数 图书馆。 因为政府会影响关键词如何行为,它 变化是非常重要的,以确保一个测试用例不 意外地影响其他测试用例。 这种依赖关系 创建不易调试的问题,例如,当新的测试用例 添加和使用图书馆不一致。
机器人框架试图保持独立于每个测试用例 其他:默认情况下,它会创建新实例的测试库 每一个测试用例。 然而,这种行为并不总是可取的, 因为有时测试用例应该能够共享一个共同的 状态。 此外,所有库没有状态和创建 其中新实例是不需要的。
。 这个属性必须 一个字符串,它可以有以下三个值:
测试用例- 为每个测试用例创建一个新的实例。 一个可能的套件设置 和套房拆卸共享另一个实例。 这是默认的。
测试套件- 创建一个新的实例为每个测试套件中。 体现测试 套房,从测试用例创建文件和包含的测试用例 自己的实例,和高级套房都得到自己的实例 可能的设置和拆解。
全球- 只有一个实例被创建在整个测试执行它 是共享的所有测试用例和测试套件。 库创建的 模块总是全局的。
请注意
, 每次创建一个新实例范围无关。
关键字为 轻松关闭所有打开的浏览器。
范围:
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
范围:
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;
}
}
指定库版本
入关键字也写这个信息 它所产生的文件。
。
:
__version__ = '0.1'
def keyword():
pass
:
public class VersionExample {
public static final String ROBOT_LIBRARY_VERSION = "1.0.2";
public void keyword() {
}
}
指定文档格式
属性。
模块安装时生成的文档。
章的更多信息 记录测试库。
"""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() {
}
}
图书馆作为侦听器
部分。
创建静态关键字
什么方法被认为是关键字
。
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();
}
}
在下面的示例中,不是 意外暴露为关键词。
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
关键字的名字
关键字的测试数据。
文件:
def hello(name):
print "Hello, %s!" % name
def do_nothing():
pass
文件:
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
使用自定义关键字的名字
可以使用一个设置的快捷方式吗 使用时,这个属性如下:
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}
不改变 关键字的名字。
语法。
关键字标签
decorator可能用作设置这个属性,当作为一个快捷方式 如下:
from robot.api.deco import keyword
@keyword(tags=['tag1', 'tag2'])
def login(username, password):
# ...
@keyword('Custom name', ['tags', 'here'])
def another_example():
# ...
前缀和由逗号分隔。 为 例子:
def login(username, password):
"""Log user in to SUT.
Tags: tag1, tag2
"""
# ...
关键字参数
有其他方式来分享吗 这个信息,所以这部分是不相关的。
最常见的,也是最简单的情况是当一个字需要一个 确切的数量的参数。 在这种情况下,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)
请注意
。
默认值为关键字
通常很有用的关键字使用的参数 默认值。 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)
这个值, 和调用关键字与多个参数失败。 在 第二个例子,一个参数永远是必需的,但第二和 第三个有默认值,因此可以使用关键字 有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变量数目的参数
定义变量的数量 参数。 例如,以下两个关键字在功能上是相同的 上述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);
}
}
使用。 这是说明 通过下面的例子,它在功能上是相同的 之前的:
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);
}
}
请注意
是支持可变参数,不是的吗 它的子类型。
。
)
。 在这个 节中,我们来看看如何使用自定义测试库。
与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'.
。
下面的例子说明了如何正常的参数,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关键字参数
作为最后一个参数来指定它们 接受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不能有一个以上的签名。
参数类型
基本类型也自动强迫。
参数类型与Python
因为参数在Python中没有任何类型的信息, 不可能时自动将字符串转换为其他类型 使用Python库。 调用一个Python方法实现一个关键字 正确数量的参数总是成功,但执行 失败后,如果参数是不相容的。 幸运的是,Python 是简单的关键词:内参数转换为适当的类型
def connect_to_host(address, port=25):
port = int(port)
# ...
参数类型与Java
Java方法的参数类型,所有的基本类型 自动处理的。 这意味着参数是正常的 字符串的测试数据是正确的类型在运行时强制。 的 可以强迫类型:
- )
- )
- 类型
- java.lang.Integer
。
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
。
使用修饰符
创建signature-preserving修饰符。
将参数嵌入到关键字的名字
为关键字 包括所需的语法。
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
与机器人交流框架
后一种方法实现一个关键字,它可以使用任何 与被测系统通信机制。 它还可以 将消息发送到机器人框架的日志文件,返回的信息 可以保存到变量,最重要的是,报告如果 关键字了。
报告关键字状态
。
。
对你例外。
Python:
class MyError(RuntimeError):
ROBOT_SUPPRESS_NAME = True
Java:
public class MyError extends RuntimeException {
public static final boolean ROBOT_SUPPRESS_NAME = true;
}
在所有情况下,重要的是用户,异常消息 尽可能的丰富。
HTML错误消息
:
raise AssertionError("*HTML* <a href='robotframework.org'>Robot Framework</a> rulez!!")
。
自动切割长消息
如果超过40行错误消息,它将自动 从中间切防止报告太长 难以阅读。 完整的错误消息总是显示在日志中 消息失败的关键字。
回溯
。
停止测试执行
从关键字值集的异常。 在下面的例子中对此进行了阐述。
Python:
class MyFatalError(RuntimeError):
ROBOT_EXIT_ON_FAILURE = True
Java:
public class MyFatalError extends RuntimeException {
public static final boolean ROBOT_EXIT_ON_FAILURE = true;
}
继续测试执行,尽管失败
值的异常 用来交流的失败。 这是证明了下面的例子。
Python:
class MyContinuableError(RuntimeError):
ROBOT_CONTINUE_ON_FAILURE = True
Java:
public class MyContinuableError extends RuntimeException {
public static final boolean ROBOT_CONTINUE_ON_FAILURE = true;
}
日志信息
。
。 消息写入标准错误处理 同样否则,但是他们回到原来的stderr回荡 关键字后执行完成。 它就可以使用 stderr如果你需要一些消息显示在控制台的地方 测试执行。
使用日志级别
。
错误和警告
在日志中 文件。 这使得这些消息比其他人更明显,并允许 使用它们重要但非关键问题报告给用户。
请注意
在机器人Framework 2.9,新功能添加到自动 将错误记录通过关键词添加到测试执行错误部分。
日志的HTML
标签可以毁了 日志文件相当严重。
启用登录HTML格式。
时间戳
默认消息记录通过标准输出或错误流 执行关键字结束的时候得到他们的时间戳。 这意味着 时间戳是不准确的,尤其是在调试问题 长期运行的关键字可以有问题。
用冒号分开:
*INFO:1308435758660* Message with timestamp *HTML:1308435758661* <b>HTML</b> message with timestamp
。
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库。
。 当 使用这种方法,消息立即写入控制台 而不是写入日志文件:
import sys
def my_keyword(arg):
sys.__stdout__.write('Got arg %s\n' % arg)
:
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)
日志的例子
是有用的,如果任何 的格式是必要的。
。
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
。
。 下面是 一个简单的使用例子:
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!')
模块。
模块
, 但是日志HTML消息或写消息到控制台 支持。 一个大好处,也显露了简单的例子 下面是使用这个日志API创建并不依赖于机器人 框架。
import logging
def my_keyword(arg):
logging.debug('Got argument %s' % arg)
do_something()
logging.info('This is a boring example')
的水平。
记录在库初始化
部分在日志文件中。
。 下面演示了这两种。
通过在初始化期间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():
# ...
请注意
。
返回值
在测试数据作为输入,然后用于其他关键词, 甚至在不同的测试库。
访问对象属性。
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
当使用线程通信
如果图书馆使用线程时,它通常与沟通 仅从主线程框架。 如果一个工作线程, 例子中,未能报告或记录的东西,它应该通过 第一个主线程的信息,可以使用异常或 其他机制在这一节中沟通的解释 框架。
当线程运行在后台,这尤其重要 其他关键字正在运行。 沟通的结果 框架在这种情况下是未定义的,在最坏的情况下会导致 崩溃或损坏输出文件。 如果一个关键字开始的东西 背景,应该有另一个关键字,检查的状态 工作线程和报告收集相应的信息。
是默默地忽略。
将节省的背景信息,这样他们以后可以吗 机器人的日志记录。
分发测试库
记录库
与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() {
}
}
。
并显示在测试日志中。 然而,后者 不使用Java库使用静态API, 因为他们的文件是迷失在编译和不可用 在运行时。
章关于格式的更多信息。
请注意
或创建文档字符串是Unicode。
测试库
任何有价值的图书馆需要全面测试,防止测试 bug。 当然,这个测试应该自动化 当库改变容易重新运行测试。
Python和Java都有优秀的单元测试工具,并且他们套件 很好测试库。 不存在重大的差异 使用它们为此目的而使用一些其他的 测试。 熟悉这些工具的开发人员不需要学习 新的东西,开发人员不熟悉他们应该学习 他们无论如何。
,这是有用的关键词报告错误的测试 正确。
是否使用一个单位或验收标准测试方法取决于 上下文。 如果有需要模拟实际系统 测试中,通常更容易在单元级别。 另一方面, 验收测试确保关键词做机器人 框架。 如果你不能决定,当然可以同时使用 的方法。
包装库
相应的行动。 更多的 复杂的图书馆应该被打包安装 更容易。
。
那 自动。
不以为然的关键词
。 这使它更容易找到旧的关键词 测试数据和删除或替换他们。
都是有效的标记。
后 弃用标记(如果有的话)。 例如,如果以下 执行关键字时,会出现一个警告信息,就像下面所示的日志文件。
def example_keyword(argument):
"""*DEPRECATED!!* Use keyword `Other Keyword` instead.
This keyword does something to given ``argument`` and returns results.
"""
return do_something(argument)
因为 他们的文档在运行时不可用。 这样的关键字, 它可以使用用户关键词包装和轻视他们。
请注意
。
动态库API
动态API是在很多方面类似于静态API。 为 关键字状态报告,记录,并返回值 完全相同的方式工作。 最重要的是,没有差异 在进口相比,动态库和使用他们的关键词 其他库。 换句话说,用户不需要知道他们的api 图书馆使用。
只有静态和动态库之间的区别 机器人框架如何发现什么关键词库实现, 这些关键字参数和文档,以及如何 关键词是实际执行。 与静态API,这一切都是 通过使用反射(Java库的文件除外), 但是动态库用于这些有特殊的方法 目的。
。
另一个主要的用例动态API实现图书馆 所以它是代表可能运行在一个实际的图书馆 甚至一些其他进程或另一台机器上。 这样的一个代理 图书馆可以很薄,因为关键字名称和所有其他 信息动态,没有需要更新的代理 当新的关键字添加到实际的库。
之前实现自己的系统。 这组 可重用的工具支持多种方式创建关键字,它是 可能已经有一个机制,套房您的需求。
获取关键字的名字
建议在使用Java。 这 方法不能采取任何参数,它必须返回一个列表或数组 字符串包含的名称关键词库中实现的。
。
动态库必须总是有这种方法。 如果它丢失,或 如果调用失败由于某种原因,图书馆被认为是 静态库。
标记方法公开为关键词
更多关于这个修饰符。
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):
# ...
运行关键字
。 第二个参数是 列表或数组的参数测试数据的关键字。
部分 更多细节关于使用kwargs与动态测试库。
对返回的东西。
但是其他的方法在动态方法 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)
获取关键字参数
在上面的例子中 可以使用任意数量的参数。 这是有问题的, 因为大多数真正的关键词期望一定数量的关键字,和 在这种情况下,他们需要检查参数计数 他们自己。
)方法。 这个方法取这个名字 的一个关键字作为参数,并返回一个列表或数组的字符串 包含关键字的参数接受。
同样作为静态关键词,动态关键字可以要求任何号码 参数的默认值,并接受变量的数量 参数和关键字参数。 如何表示的语法 所有这些不同的变量在下面的表格说明。 注意,列表的例子使用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
|
| 变量的数量 的参数 (可变参数) | 它的名字。 |
['*varargs']
['a', 'b=42', '*rest']
|
0 /任何
1 /任何
|
| 免费的关键字 参数(kwargs) | 它的名字。 |
['**kwargs']
[a,b = 42 ',' * * kws ']['*varargs', '**kwargs']
|
0/0
1/2
0 /任何
|
甚至没有。
工具需要能够创建一个有意义的库文件。
通过三个参数。
获取关键字的文档
)。 需要作为一个关键字的名字 参数,方法名称所暗示的,返回的文档 一个字符串。
)是 测试日志中所示。
获取关键字标签
方法可以被添加到动态API 以后如果有需要。
让通用库文档
好多了。
在实践中。
方法,后者优先。
命名参数语法与动态库
方法。
方法。
。 评论显示关键字实际上是调用的参数。
*** 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]
免费的关键字参数与动态库
: 第三个将kwargs时使用。 Kwargs传递到 关键字作为一个字典(Python)或地图(Java)。
关键字是 确认接受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 |
是可选的。 |
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);
}
请注意
。
。
复合library API
复合图书馆的API,顾名思义,之间的混合 静态API和动态API。 就像动态API,它是 可能实现图书馆使用混合API类。
获取关键字的名字
方法返回 图书馆实现的关键字名称的列表。
运行关键字
方法执行 关键词。 相反,机器人框架使用反射来发现方法 实现关键字,同样与静态API。 一个图书馆 使用混合API可以实现这些方法 直接或,更重要的是,它可以动态地处理它们。
第一。
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)
动态API。 相反,它只 返回一个可调用对象,然后执行的机器人框架。
。
混合使用Java API不是很有用,因为它不是 可能处理缺失的方法。 当然,这是可能的 实现类中的所有方法库,但这带来了一些 好处相比静态API。
关键字参数和文档
当使用这个API时,机器人框架使用反射来发现 方法实现关键词,同样与静态API。 后 得到一个参考方法,它对参数和搜索 文档,使用静态时相同的方式 API。 因此不需要特殊的方法得到参数 和文档如有动态API。
总结
和其他人 可以直接在主库类来实现。
由于明显的好处和同等能力,混合API 在大多数情况下是一个更好的选择比动态API在使用吗 Python。 一个值得注意的例外是实现图书馆作为一个代理 一个实际的库实现在其他地方,因为实际 关键字必须执行其他地方,代理只能向前传递 关键字名称和参数。
图书馆。
使用机器人框架的内部模块
测试库使用Python实现可以使用机器人框架的 内部模块,例如,要获取的信息执行 测试和使用的设置。 这个强大的机制 与框架应小心使用,不过, 因为所有机器人框架的api并不意味着使用 不同框架之间的外部,他们可能会彻底改变 版本。
可用的api
。
使用内建库
。
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>'
模块。 这种方法的文档解释道 为什么需要这样做,显然还怎么做。
扩展现有测试库
本节解释不同的方法如何添加新的 功能对现有测试库和如何使用它们 否则自己的库。
修改原始源代码
如果你有访问库的源代码 自然扩展,你可以直接修改源代码。 最大的 这种方法的问题是,很难给你更新 原来的图书馆在不影响您的更改。 用户也可以 被混淆使用图书馆,有不同的功能 最初的一个。 也可能是一个额外的重新包装图书馆 的任务。
这种方法是通用的,非常好用,如果增强 你打算报回到最初的开发人员。 如果你的 更改应用到原始库,它们包含在 未来版本和上面讨论的所有问题是减轻。 如果 变化非泛型,或者因为其他原因不能提交 回来,在后续部分中解释的方法 可能做得更好。
使用继承
。 这 示例使用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))
。
*** Settings ***
Library SeleniumLibrary
Library SeLibExtensions
*** Test Cases ***
Example
Open Browser http://example # SeleniumLibrary
Title Should Start With Example # SeLibExtensions
使用动态库或混合API
经常 有自己的系统如何扩展它们。 使用这些库 从图书馆需要问指导开发人员或咨询 库文件或源代码。