4.3使用监听器接口

Robot Framework有一个侦听器接口,可用于接收有关测试执行的通知。监听器是具有某些特殊方法的类或模块,它们可以用Python和Java实现。监听器接口的示例用法包括外部测试监视器,在测试失败时发送邮件消息以及与其他系统通信。

4.3.1使用听众

使用--listener 选项从命令行使用监听器,以便将监听器的名称作为参数提供给它。侦听器名称来自实现侦听器接口的类或模块的名称,类似于从实现它们的类获取测试库名称。指定的侦听器必须位于导入导入时搜索测试库的同一模块搜索路径中。其他选项是提供侦听器文件的绝对路径或相对路径, 与测试库类似。通过多次使用此选项,可以使用多个侦听器。

也可以从命令行为监听器类提供参数。使用冒号作为分隔符在侦听器名称(或路径)之后指定参数。此方法仅提供字符串类型参数,并且参数显然不能包含冒号。但是,听众应该很容易绕过这些限制。

例子:

pybot --listener MyListener tests.html
jybot --listener com.company.package.Listener tests.html
pybot --listener path/to/MyListener.py tests.html
pybot --listener module.Listener --listener AnotherListener tests.html
pybot --listener ListenerWithArgs:arg1:arg2
pybot --listener path/to/MyListener.java:argument tests.html

4.3.2可用的侦听器接口方法

在测试执行开始时,Robot Framework使用给定的参数创建一个侦听器类的实例。在测试执行期间,当测试套件,测试用例和关键字开始和结束时,Robot Framework会调用侦听器的方法。它还在输出文件准备好时调用适当的方法,最后在调用close方法时调用。监听器不需要实现任何官方接口,它只需要具有它实际需要的方法。

监听器接口版本

在Robot Framework 2.1中更改了与测试执行进度相关的方法的签名。进行此更改以便可以在不破坏现有侦听器的情况下将新信息添加到侦听器接口。旧签名将继续有效,但在将来的某个版本中将被弃用,因此所有新的侦听器都应使用下表中描述的签名来实现。有关旧侦听器接口的最新详细说明,请参阅Robot Framework 2.0.4的用户指南。

注意

侦听器必须 定义属性ROBOT_LISTENER_API_VERSION才能被识别为新样式侦听器。ROBOT_LISTENER_API_VERSION属性的值 必须为2,可以是字符串,也可以是整数。以下示例实现为新样式侦听器。

监听器接口方法签名

与测试执行进度相关的所有侦听器方法都具有相同的签名方法(名称,属性),其中属性 是包含事件详细信息的字典。下表列出了侦听器界面中的所有可用方法以及属性字典的内容(如果适用)。字典的键是字符串。所有这些方法都有 别名。因此,例如,startSuite是同义词start_suite。

start_suite

名称,属性

name, attributes

属性字典中的键:

  • longname:套件名称,包括父套件
  • doc:测试套件文档
  • metadata:包含免费测试套件元数据的字典/地图(2.5中的新内容)
  • source:文件/目录测试套件的绝对路径是从(2.7中的新增内容)创建的
  • suites:直接在此套件中的套件名称作为字符串列表(2.5中的新增内容)
  • tests:直接在此套件中作为字符串列表的测试名称(2.5中的新增内容)
  • totaltests:此套件及其所有子套件中的测试总数为整数(2.5的新增内容)
  • starttime:执行开始时间
end_suite

名称,属性

name, attributes

属性字典中的键:

  • longname:测试套件名称,包括父母
  • doc:测试套件文档
  • metadata:包含免费测试套件元数据的字典/地图(2.6中的新内容)
  • source:文件/目录测试套件的绝对路径是从(2.7中的新增内容)创建的
  • starttime:执行开始时间
  • endtime:执行结束时间
  • elapsedtime:以整数形式执行的时间(以毫秒为单位)
  • status:通过或失败
  • statistics:套件统计信息(套件中已通过和未通过的测试次数)作为字符串
  • message:如果套件设置或拆卸失败,则显示错误消息,否则为空
start_test

名称,属性

name, attributes

属性字典中的键:

  • longname:测试名称包括父套件
  • doc:测试用例文档
  • tags:测试用例标签作为字符串列表
  • critical:是或否取决于测试被认为是否关键(2.6中的新内容)
  • template:包含用于测试的模板的名称。如果测试没有模板化,那么它将是一个空字符串(2.6中的新内容)
  • starttime:执行开始时间
end_test

名称,属性

name, attributes

属性字典中的键:

  • longname:测试名称包括父套件
  • doc:测试用例文档
  • tags:测试用例标签作为字符串列表
  • critical:是或否取决于测试被认为是否关键(2.6中的新内容)
  • template:包含用于测试的模板的名称。如果测试没有模板化,那么它将是一个空字符串(2.6中的新内容)
  • starttime:执行开始时间
  • endtime:执行结束时间
  • elapsedtime:以整数形式执行的时间(以毫秒为单位)
  • status:通过或失败
  • message:状态消息,通常是错误消息或空字符串
start_keyword

名称,属性

name, attributes

属性字典中的键:

  • type:字符串关键字正常关键字和测试设置,测试拆解,Suite安装或套房拆解在套房/测试设置/拆卸用于关键字(在2.6新)
  • doc:关键字文档
  • args:关键字的参数作为字符串列表
  • starttime:执行开始时间
end_keyword

名称,属性

name, attributes

属性字典中的键:

  • type:与start_keyword相同
  • doc:关键字文档
  • args:关键字的参数作为字符串列表
  • starttime:执行开始时间
  • endtime:执行结束时间
  • elapsedtime:以整数形式执行的时间(以毫秒为单位)
  • status:通过或失败
log_message

信息  message

在执行的关键字写入日志消息时调用。message是一个包含以下键的字典:

  • message:消息的内容
  • level:记录消息时使用的日志级别
  • timestamp:消息创建时间,格式为 YYYY-MM-DD hh:mm:ss.mil
  • html:string yes或no表示消息是否应该被解释为HTML

信息  message

信息  message

在框架本身写入系统日志 消息时调用。message是一个与log_message方法具有相同键的字典。

输出文件  output_file路径  path完成写入输出文件时调用。路径是文件的绝对路径。
log_file路径  path完成写入日志文件时调用。路径是文件的绝对路径。
报告文件  report_file路径  path写入报告文件时调用已完成。路径是文件的绝对路径。
debug_file路径  path写入调试文件时调用完成。路径是文件的绝对路径。
close 在所有测试套件及其中的测试用例之后调用已经执行。

可用的方法及其参数也显示在下面的正式Java接口规范中。所述的内容java.util.Map属性是如在上面的表格。应该记住,监听不需要实现任何显式接口或具有所有这些方法。

public interface RobotListenerInterface {
public static final int ROBOT_LISTENER_API_VERSION = 2;
void startSuite(String name, java.util.Map attributes);
void endSuite(String name, java.util.Map attributes);
void startTest(String name, java.util.Map attributes);
void endTest(String name, java.util.Map attributes);
void startKeyword(String name, java.util.Map attributes);
void endKeyword(String name, java.util.Map attributes);
void logMessage(java.util.Map message);
void message(java.util.Map message);
void outputFile(String path);
void logFile(String path);
void reportFile(String path);
void debugFile(String path);
void close();
}

4.3.3监听器记录

Robot Framework 2.6引入了新的编程日志API,听众也可以使用它们。但是,存在一些限制,以及下表中解释了不同的侦听器方法如何记录消息。

start_keyword,end_keyword,log_message消息将记录到 execution关键字下的普通日志文件中。
start_suite,end_suite,start_test,end_test消息将记录到syslog中。警告也显示在普通日志文件的执行错误部分中。
信息消息通常记录在syslog中。如果在执行关键字时使用此方法,则会将消息记录到普通日志文件中。
其他方法消息仅记录到syslog中。
start_keyword, end_keyword, log_messageMessages are logged to the normal log file under the executed keyword.
start_suite, end_suite, start_test, end_testMessages are logged to the syslog. Warnings are shown also in the execution errors section of the normal log file.
messageMessages are normally logged to the syslog. If this method is used while a keyword is executing, messages are logged to the normal log file.
Other methodsMessages are only logged to the syslog.
 

注意

为避免递归,侦听器记录的消息不会发送到侦听器方法log_message和message。

警告

在Robot Framework 2.6.2之前,侦听器的日志记录存在严重问题。因此不建议在早期版本中使用此功能。

4.3.4监听器示例

第一个简单示例在Python模块中实现。它主要说明使用监听器接口并不是很复杂。

ROBOT_LISTENER_API_VERSION = 2

def start_test(name, attrs):
print 'Executing test %s' % name def start_keyword(name, attrs):
print 'Executing keyword %s with arguments %s' % (name, attrs['args']) def log_file(path):
print 'Test log available at %s' % path def close():
print 'All tests executed'

第二个仍然使用Python的例子稍微复杂一些。它将获取的所有信息写入临时目录中的文本文件,而不需要太多格式化。文件名可以从命令行给出,但也有默认值。请注意,在实际使用中, 通过命令行选项--debugfile提供的调试文件功能可能比此示例更有用。

import os.path
import tempfile class PythonListener: ROBOT_LISTENER_API_VERSION = 2 def __init__(self, filename='listen.txt'):
outpath = os.path.join(tempfile.gettempdir(), filename)
self.outfile = open(outpath, 'w') def start_suite(self, name, attrs):
self.outfile.write("%s '%s'\n" % (name, attrs['doc'])) def start_test(self, name, attrs):
tags = ' '.join(attrs['tags'])
self.outfile.write("- %s '%s' [ %s ] :: " % (name, attrs['doc'], tags)) def end_test(self, name, attrs):
if attrs['status'] == 'PASS':
self.outfile.write('PASS\n')
else:
self.outfile.write('FAIL: %s\n' % attrs['message']) def end_suite(self, name, attrs):
self.outfile.write('%s\n%s\n' % (attrs['status'], attrs['message'])) def close(self):
self.outfile.close()

第三个示例实现与前一个示例相同的功能,但使用Java而不是Python。

import java.io.*;
import java.util.Map;
import java.util.List; public class JavaListener { public static final int ROBOT_LISTENER_API_VERSION = 2;
public static final String DEFAULT_FILENAME = "listen_java.txt";
private BufferedWriter outfile = null; public JavaListener() throws IOException {
this(DEFAULT_FILENAME);
} public JavaListener(String filename) throws IOException {
String tmpdir = System.getProperty("java.io.tmpdir");
String sep = System.getProperty("file.separator");
String outpath = tmpdir + sep + filename;
outfile = new BufferedWriter(new FileWriter(outpath));
} public void startSuite(String name, Map attrs) throws IOException {
outfile.write(name + " '" + attrs.get("doc") + "'\n");
} public void startTest(String name, Map attrs) throws IOException {
outfile.write("- " + name + " '" + attrs.get("doc") + "' [ ");
List tags = (List)attrs.get("tags");
for (int i=0; i < tags.size(); i++) {
outfile.write(tags.get(i) + " ");
}
outfile.write(" ] :: ");
} public void endTest(String name, Map attrs) throws IOException {
String status = attrs.get("status").toString();
if (status.equals("PASS")) {
outfile.write("PASS\n");
}
else {
outfile.write("FAIL: " + attrs.get("message") + "\n");
}
} public void endSuite(String name, Map attrs) throws IOException {
outfile.write(attrs.get("status") + "\n" + attrs.get("message") + "\n");
} public void close() throws IOException {
outfile.close();
} }
04-20 15:37