创建测试库类或模块

测试库的实现可以是Python模块, 也可以是Python或Java的类.

测试库名称

测试库引入(import)时需要指定名称, 这个名称和实现测试库的模块名或类名一样.

举个例子, 如果有个Python模块 MyLibrary (文件是 MyLibrary.py), 这就可作为一个测试库: MyLibrary. 类似的, 一个不在任何包里面的Java类 YourLibrary, 就是一个同名的测试库.

Python的类总是在模块里, 如果模块里实现的类的名称和模块名一致, Robot Framework允许不带类名来引用这个库. 例如, 有一个类 MyLib 在文件 MyLib.py 中,引用库时只需使用名称 MyLib 即可. 这个机制对于子模块同样有效, 如,parent.MyLib 模块中有个类 MyLib, 使用 parent.MyLib 即可导入.但是, 如果模块名和类名不一样, 则必须同时指明, 如 mymodule.MyLibrary或者 parent.submodule.MyLib.

非默认包里的Java类也必须指定全名, 例如, 包 com.mycompany.myproject 里的类 MyLib 导入名称是: com.mycompany.myproject.MyLib.

注解

在同名模块中忽略类名只在 Robot Framework 2.8.4 及之后的版本有效.老的版本中仍然需要指定全名, 如 parent.MyLib.MyLib.

小技巧

如果库名确实太长了, 比如Java的包名太长, 推荐使用 测试库设置别名给库起个别名.

给测试库提供参数

实现为类的测试库都可以接受参数. 这些参数在Setting表中指定, 跟在库名后面,当Robot Framework创建测试库的实例时, 把这些参数传给构造函数.

实现为模块的测试库不可以接受参数, 试图给其传递参数的行为将导致报错.

库所需的参数的个数和库的构造函数的参数个数一样. 默认参数和不定数量参数的处理类似于 关键字参数. Java库不支持不定数量的参数.

传递给库的参数, 包括库名本身, 都可以使用变量. 也就是说可以在某些时候, 例如命令行, 修改它们.

  1. *** Settings ***
  2. Library MyLibrary 10.0.0.1 8080
  3. Library AnotherLib ${VAR}

下面是上面的例子中库的实现, 第一个是Python, 第二个是Java:

  1. from example import Connection
  2.  
  3. class MyLibrary:
  4.  
  5. def __init__(self, host, port=80):
  6. self._conn = Connection(host, int(port))
  7.  
  8. def send_message(self, message):
  9. self._conn.send(message)
  1. public class AnotherLib {
  2.  
  3. private String setting = null;
  4.  
  5. public AnotherLib(String setting) {
  6. setting = setting;
  7. }
  8.  
  9. public void doSomething() {
  10. if setting.equals("42") {
  11. // do something ...
  12. }
  13. }
  14. }

测试库的作用域

用类实现的库可以有内部状态, 这些状态可以被关键字或构造函数修改. 因为这些状态会影响到关键字实际的行为, 所以, 保证一个测试用例不会意外地影响到另一个用例显得非常重要. 这种依赖行为有可能造成非常难定位的bug. 例如, 添加了新的测试用例,而这些用例使用库的方式并不一致.

Robot Framework 为了保证测试用例之间的独立性, 默认情况下, 它为每个测试用例创建新的测试库实例. 然而, 这种方式不总是我们想要的, 比如有时测试用例需要共享某个状态的时候. 此外, 那些无状态的库显然也不需要每次都创建新实例.

实例化测试库类的方式可以通过一个特别的属性 ROBOT_LIBRARY_SCOPE 来控制.这个属性是一个字符串, 可以有以下三种取值:

  • TEST CASE
  • 为每个测试用例创建新的实例. 如果有suite setup和suite teardown的话, 同样也会新建. 这是默认行为.
  • TEST SUITE
  • 为每个测试集创建新的实例. 最底层的测试集, 也就是由测试用例文件组成的测试集,拥有属于自己的测试库实例, 高层的测试集, 都有属于自己的测试库实例.
  • GLOBAL
  • 整个测试执行过程中只有一个实例被创建. 所有的测试集和测试用例共享这个实例.通过模块创建的测试库都是全局的.

注解

如果一个测试库被导入多次, 每次使用不同的参数,则不管有没有定义作用域, 每次都会新建一个实例.

当有状态的测试库定义了作用域为 TEST SUITEGLOBAL , 建议测试库要包含能清除这些状态的关键字. 这样, 在测试集 setup 或 teardown 时, 可以调用这些关键字以保证下面的测试用例从一个明确的已知状态开始.

例如, SeleniumLibrary 使用了 GLOBAL 作用域, 使得不同的测试用例使用相同的浏览器, 而不是每次重新打开. 同时, 它还提供了关键字Close All Browsers 关闭所有浏览器.

下面是使用了 TEST SUITE 作用域的Python库的示例:

  1. class ExampleLibrary:
  2.  
  3. ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
  4.  
  5. def __init__(self):
  6. self._counter = 0
  7.  
  8. def count(self):
  9. self._counter += 1
  10. print self._counter
  11.  
  12. def clear_counter(self):
  13. self._counter = 0

使用了 GLOBAL 作用域的Java库的示例:

  1. public class ExampleLibrary {
  2.  
  3. public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";
  4.  
  5. private int counter = 0;
  6.  
  7. public void count() {
  8. counter += 1;
  9. System.out.println(counter);
  10. }
  11.  
  12. public void clearCounter() {
  13. counter = 0;
  14. }
  15. }

指定测试库的版本

当一个测试库投入使用, Robot Framework 会尝试获取它的版本号, 将该信息写入到 日志_ 中以供调试. 库文档工具 Libdoc_ 在生成文档时也会写入该信息.

版本号信息在属性 ROBOT_LIBRARY_VERSION 中定义, 类似 测试库的作用域中的 ROBOTLIBRARYSCOPE. 如果 ROBOT_LIBRARY_VERSION 属性不存在,则会尝试从 __version 属性获取. 这些属性必须是类或者模块的属性.对于Java库, 这个属性必须声明为 static final.

使用 version 的Python模块示例:

  1. __version__ = '0.1'
  2.  
  3. def keyword():
  4. pass

使用 ROBOT_LIBRARY_VERSION 的Java类示例:

  1. public class VersionExample {
  2.  
  3. public static final String ROBOT_LIBRARY_VERSION = "1.0.2";
  4.  
  5. public void keyword() {
  6. }
  7. }

指定文档格式

从 Robot Framework 2.7.5版本开始, 库文档工具 Libdoc_ 开始支持多种格式.如果不想使用 Robot Framework’s 自己的 文档格式, 可以通过在源码中定义属性 ROBOT_LIBRARY_DOC_FORMAT 来指定格式, 就跟指定 作用域版本 一样.

文档格式可指定的值包括: ROBOT (默认), HTML, TEXT (纯文本),和 reST (reStructuredText_). 这些值不区分大小写. 如果要使用 reST格式需要安装 docutils_ 模块.

下面使用Python和Java设置文档格式的例子分别使用了 reStructuredText 和 HTML格式. 关于给测试库写文档的更多内容, 请参考 测试库的文档Libdoc_ 章节.

  1. """A library for *documentation format* demonstration purposes.
  2.  
  3. This documentation is created using reStructuredText__. Here is a link
  4. to the only \`Keyword\`.
  5.  
  6. __ http://docutils.sourceforge.net
  7. """
  8.  
  9. ROBOT_LIBRARY_DOC_FORMAT = 'reST'
  10.  
  11. def keyword():
  12. """**Nothing** to see here. Not even in the table below.
  13.  
  14. ======= ===== =====
  15. Table here has
  16. nothing to see.
  17. ======= ===== =====
  18. """
  19. pass
  1. /**
  2. * A library for <i>documentation format</i> demonstration purposes.
  3. *
  4. * This documentation is created using <a href="http://www.w3.org/html">HTML</a>.
  5. * Here is a link to the only `Keyword`.
  6. */
  7. public class DocFormatExample {
  8.  
  9. public static final String ROBOT_LIBRARY_DOC_FORMAT = "HTML";
  10.  
  11. /**<b>Nothing</b> to see here. Not even in the table below.
  12. *
  13. * <table>
  14. * <tr><td>Table</td><td>here</td><td>has</td></tr>
  15. * <tr><td>nothing</td><td>to</td><td>see.</td></tr>
  16. * </table>
  17. */
  18. public void keyword() {
  19. }
  20. }

作为监听器的测试库

监听器接口 可以让外部的监听器在测试执行过程中得到关于执行状态的通知.例如, 当测试集, 测试用例和关键字开始执行或结束. 有时候这些通知对测试库来说很有用, 可以使用 ROBOT_LIBRARY_LISTENER 注册一个自定义的监听器.该属性的值应该是要使用的监听器的示例, 有可能是测试库本身. 更多内容和示例,请参考 作为监听器的测试库 section.