本主题描述可扩展性 API,它允许通过在指定的时间间隔进行轮询、在测试执行后进行轮询以及订阅事件生成器来捕获事件。

章节目录:

Javadocs 在哪里?

可以通过选择 Parasoft> 帮助帮助 > 帮助内容(取决于您的安装程序),然后打开 Parasoft SOAtest Extensibility API 手册访问 Javadocs。与事件监控器工具直接相关的资源有 com.parasoft.api.IEvent,它的默认实现适配器 com.parasoft.api.Event,和 com.parasoft.api.EventSubscriber

可用模式

可扩展性 API 允许使用以下三种模式之一捕获事件:

在指定的时间间隔进行轮询

当尝试监控的系统中的事件与测试执行不同步时,此模式非常有用。例如,您可能对从日志框架中提取数据感兴趣,该框架以指定的时间间隔记录事件,因此您希望以相同的时间间隔在 SOAtest 中捕获已记录的事件,以确保实际检索到这些事件。

与此类似的是,某人是某一特定月刊的粉丝,但不是为了收到每一期已出版的杂志而订阅它,读者每月都会去书店购买最新一期。

这种模式的一个有趣之处在于,如果您在新事件可用之前对事件进行轮询,那么您可能会得到与上次轮询相同的事件,或者根本没有事件(这取决于您的目标框架的行为)。这就像我们的示例阅读器可能在商店中只找到上个月的一期,因为当前的一期还没有发布。 

使用此模式,您可以指定一个时间量(以毫秒为单位),它将作为脚本执行之间的等待期。例如,如果将间隔指定为 1000 毫秒,则事件监控工具将会每秒执行您提供的代码。这种情况将持续到发生以下两个事件之一:

  1. 如果事件监控器执行测试套件的一部分与其他各种测试,定期用户代码执行就会停止最后一个测试在测试套件(或者数据源中的最后一行,前提为:测试套件测试是遍历一个数据源)完成执行。
  2. 已达到最大监控执行持续时间(该值在“选项”选项卡下配置)。

在每次测试执行之后进行轮询

当试图监控系统中的事件通常与测试套件的测试执行事件同步时,此模式非常有用。例如,在系统中发生事件之后,系统的日志框架会立即被触发,并且这些事件可供您获取。

使用此模式,您提供的代码将在测试套件中的每个测试执行之后立即执行。如果您单独运行事件监控工具(除了执行包含它的整个测试套件之外),则此模式不适用。在这种情况下,事件监控将停止一次:

  1. 测试套件中的最后一个测试(如果测试套件测试在数据源上迭代,则是数据源中的最后一行)已经执行完毕。
  2. 已达到最大监控执行持续时间(该值在“选项”选项卡下配置)。

订阅事件生成器

这可能是最常见的模式,Parasoft 建议尽可能使用它。当试图监控的框架允许订阅者在事件发生时立即被触发时,这种模式非常有用。换句话说,它可以执行“回调”功能。

例如,JMS 发布/订阅消息模式就是这种模式的一个例子,它用于驱动 Sonic、TIBCO 和事件监控器工具中支持的其他内置平台。在我们的杂志读者示例中,这类似于订阅出版物,因此最新一期的杂志一出版就会被交付给读者。

使用“在指定的时间间隔进行轮询”和“在每次测试执行之后进行轮询”模式

当使用这两种模式时,您在 User Code 部分中选择的方法将按照各自的模式执行。您可以将方法名称与您希望的任何名称组合在一起(请确保方法菜单中选中了该名称)。

IEvent getEvent(String url, String username, String password, Object connection, ScriptingContext context)

  • url (String): 事件监控器连接部分的 URL 字段中提供的值。
  • usernameString): 事件监控器连接部分的 username 字段中提供的值。
  • passwordString): 事件监控器连接部分的 password 字段中提供的值。
  • connection(Object): 可以选择提供此对象,以便在事件监控器的多个脚本执行过程中维护和重用相同的连接。详情请参阅Maintaining Connections
  • context (com.parasoft.api.Context): 标准的 SOAtest 脚本上下文,它允许访问变量、数据源值和设置/获取对象,以便在测试执行期间共享。

示例(Jython)

from com.parasoft.api import *
 
def getEvent(url, username, password, connection, context):
	return Event("Hello!")

getEvent() 方法下的代码基本上处理从希望监控的系统中检索事件,并返回 com.parasoft.api.IEvent 的实现。在本例中,我们返回 com.parasoft.api.Event,它是该接口的适配器实现,并接受一个简单的字符串对象“Hello!”。

保持连接

在实践中,能够创建到您希望监控并重用该连接来检索事件的远程系统的连接(而不是在每次用户代码调用时创建新的连接),这一点常常很有用。因此,除了具有如上所述的检索 Ievent 对象的方法外,您还可以选择添加两个额外的可选方法:

Object createConnection(String url, String username, String password, com.parasoft.api.Context context)

Object destroyConnection(Object connection, com.parasoft.api.Context context)

createConnection 将创建一个对象句柄并将其返回到监控连接,而 destroyConnection 接收该对象,并允许您为优雅断开连接提供代码。

事件监控器寻找这两个可选方法的存在。如果要添加,请确保使用正确的方法签名。createConnection() 在事件监视器开始执行时调用一次,destroyConnection 在结束时调用一次。事件检索方法(例如上面的 getEvent())在按照所选模式运行事件监控器测试期间可能被调用多次。使用 createConnection 方法创建的连接对象被传递给事件检索方法,因此可以使用该连接返回事件。

示例

from com.parasoft.api import *
 
def getEvent(url, username, password, connection, context):
	return connection.getEvent()

使用“订阅事件生成器”模式

使用此模式,事件监控预期存在一种方法(任意名称,只要在方法下拉菜单中选择该名称即可),并且具有以下签名:

EventSubscriber getEventSubscriber(String url, String username, String password, Context context)

在前面的模式中有提供参数说明。

在本例中,您需要提供 EventSubscriber 的 Java 实现(通过从 com.parasoft.api.EventSubscriber 继承)。具体实现方法如下:

public boolean start() Throws Exceptionpublic boolean stop() Throws Exception

事件监控开始时将自动调用 start 方法,事件监控执行结束时将自动调用 stop 方法。在此模式下的假设是,EventSubscriber 实现将负责连接到目标系统并在 start() 中订阅其事件生成框架,然后在 stop() 中取消订阅并断开连接。下面提供了订阅 TIBCO EMS 消息监控主题的示例实现。这实际上反映了事件监控内置的 TIBCO EMS 平台所使用的模式。

示例

在与 SOAtest 一起发布的 examples 脚本目录下也可以找到这个例子。它作为 Eclipse 项目包含在 zip 归档文件中,可以导入到 Eclipse 工作空间。它要求将 TIBCO EMS 的 tibjms.jar 文件和 com.parasoft.api.jar 文件添加到 classpath 中来构建和运行。com.parasoft.api.jar 位于 <INSTALL>/plugins/com.parasoft.ptest.libs.web_<VERSION>/root 目录中。

import com.parasoft.api.*; 
import com.tibco.tibjms.*; 
import javax.jms.*;
 
public class TIBCOEventSubscriber extends EventSubscriber {
    	private ConsumerRunnable _consumerRunnable;     
	private Connection _connection;
    	private String _dest;
    	private boolean _started = false;
	public TIBCOEventSubscriber(String url, String username, String password, String destination) throws JMSException {
		_dest = destination;
		QueueConnectionFactory factory = new TibjmsQueueConnectionFactory(url); 
		_connection = factory.createQueueConnection(username, password);
	}
	public boolean start() throws Exception {
		Session session = null;
		session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 
		Destination destination = session.createTopic(_dest); 
		MessageConsumer msgConsumer = session.createConsumer(destination);
		_connection.start();
		_started = true;
		_consumerRunnable = new ConsumerRunnable(msgConsumer);
		Thread thread = new Thread(_consumerRunnable);
		thread.start();
		Application.showMessage("Monitoring started on " + _dest);
		return true;
	}
 
	public boolean stop() throws Exception {
		_started = false;
		Thread.sleep(1000);
		if (_connection != null) {
			_connection.close();
			Application.showMessage("Monitoring connection closed");
		}
		if (_consumerRunnable != null && _consumerRunnable.getException() != null) {
			throw _consumerRunnable.getException();
		}
		return _started;
	}
 
	private class ConsumerRunnable implements Runnable {
		private MessageConsumer msgConsumer; 
		private Exception t;
 
		public ConsumerRunnable(MessageConsumer msgConsumer) {
			this.msgConsumer = msgConsumer;
		}
		public void run() {
			while(_started) {
				try {
					MapMessage msg = (MapMessage)msgConsumer.receive(500);
					if (msg == null) {
						continue;
					}
					Message actualMessage = null; 
					try {
						byte[] bytes = msg.getBytes("message_bytes"); 
						if (bytes != null && bytes.length > 0) {
							actualMessage = Tibjms.createFromBytes(bytes);
						}
					} catch (JMSException e1) {
					}
					// you can provide your own extension of Event in order to customize the
event
					// getLabel(), toString() and toXML() outputs 
					IEvent event;
					if (actualMessage == null) {
						event = new Event(msg);
					} else {
						event = new Event(actualMessage);
					}
					event.setTimestamp(msg.getJMSTimestamp());
					onEvent(event);
				} catch (JMSException e) {
					Application.showMessage(e.getClass().toString() + ": " + e.getMessage()); 
					try {
						msgConsumer.close();
					} catch (JMSException e1) {
						Application.showMessage(e1.getClass().toString() + ": " + e1.getMessage());
					}
					t = e;
					_started = false;
				}
			}
		}
		public Exception getException() {
			return t;
		}
	}
}



  • No labels