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,可以是字符串,也可以是整数。以下示例实现为新样式侦听器。
监听器接口方法签名
与测试执行进度相关的所有侦听器方法都具有相同的签名方法(名称,属性),其中属性 是包含事件详细信息的字典。下表列出了侦听器界面中的所有可用方法以及属性字典的内容(如果适用)。字典的键是字符串。所有这些方法都有 camelCase别名。因此,例如,startSuite是同义词start_suite。
方法 | 参数 | 属性/解释 |
---|---|---|
start_suite |
名称,属性 name, attributes |
属性字典中的键:
|
end_suite |
名称,属性 name, attributes |
属性字典中的键:
|
start_test |
名称,属性 name, attributes |
属性字典中的键:
|
end_test |
名称,属性 name, attributes |
属性字典中的键:
|
start_keyword |
名称,属性 name, attributes |
属性字典中的键:
|
end_keyword |
名称,属性 name, attributes |
属性字典中的键:
|
log_message |
信息 message |
在执行的关键字写入日志消息时调用。message是一个包含以下键的字典:
|
信息 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中。 |
Methods | Explanation |
---|---|
start_keyword, end_keyword, log_message | Messages are logged to the normal log file under the executed keyword. |
start_suite, end_suite, start_test, end_test | Messages are logged to the syslog. Warnings are shown also in the execution errors section of the normal log file. |
message | Messages 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 methods | Messages 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'
" % (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
')
else:
self.outfile.write('FAIL: %s
' % attrs['message'])
def end_suite(self, name, attrs):
self.outfile.write('%s
%s
' % (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") + "'
");
}
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
");
}