我正在尝试为我在 Flex 4.5.1 中编写的一个类编写一些单元测试,分别使用 FlexUnit 4 和Mockolate作为我的测试和模拟框架。我正在为我的自定义事件使用as3 信号。
我正在编写和测试的功能是ArcGIS API for Flex中QueryTask类的包装类 (QueryQueue) 。这使我能够轻松地将多个查询任务排队等待执行。我的包装器 QueryQueue 将在处理完所有查询响应后调度一个事件。completed
界面非常简单。
public interface IQueryQueue
{
function get inProgress():Boolean;
function get count():int;
function get completed():ISignal;
function get canceled():ISignal;
function add(query:Query, url:String, token:Object = null):void;
function cancel():void;
function execute():void;
}
这是一个示例用法:
public function exampleUsage():void
{
var queryQueue:IQueryQueue = new QueryQueue(new QueryTaskFactory());
queryQueue.completed.add(onCompleted);
queryQueue.canceled.add(onCanceled);
var query1:Query = new Query();
var query2:Query = new Query();
// set query parameters
queryQueue.add(query1, url1);
queryQueue.add(query2, url2);
queryQueue.execute();
}
public function onCompleted(sender:Object, event:QueryQueueCompletedEventArgs)
{
// do stuff with the the processed results
}
public function onCanceled(sender:Object, event:QueryQueueCanceledEventArgs)
{
// handle the canceled event
}
对于我的测试,我目前正在模拟 QueryTaskFactory 和 QueryTask 对象。简单的测试,例如确保查询被相对直接地添加到队列中。
[Test(Description="Tests adding valid QueryTasks to the QueryQueue.")]
public function addsQuerys():void
{
var queryTaskFactory:QueryTaskFactory = nice(QueryTaskFactory);
var queryQueue:IQueryQueue = new QueryQueue(queryTaskFactory);
assertThat(queryQueue.inProgress, isFalse());
assertThat(queryQueue.count, equalTo(0));
var query1:Query = new Query();
queryQueue.add(query1, "http://gisinc.com");
assertThat(queryQueue.inProgress, isFalse());
assertThat(queryQueue.count, equalTo(1));
var query2:Query = new Query();
queryQueue.add(query2, "http://gisinc.com");
assertThat(queryQueue.inProgress, isFalse());
assertThat(queryQueue.count, equalTo(2));
var query3:Query = new Query();
queryQueue.add(query3, "http://gisinc.com");
assertThat(queryQueue.inProgress, isFalse());
assertThat(queryQueue.count, equalTo(3));
}
但是,我也希望能够测试该execute
方法。此方法应执行添加到队列中的所有查询。处理完所有查询结果后,将completed
调度事件。测试应确保:
execute
在每个查询上调用一次且仅一次inProgress = true
结果尚未处理inProgress = false
处理结果时completed
在处理结果后调度canceled
从不调用(对于有效查询)- 队列内完成的处理正确处理和打包查询结果
到目前为止,我可以为项目 1 到 5 编写测试,这在很大程度上要归功于 weltraumpirat 提供的答案。我的执行测试现在看起来像这样。
[Test(async, description="Tests that all queryies in the queue are executed and the completed signal is fired")]
public function executesAllQueriesInQueue():void
{
// Setup test objects and mocks
var query:Query = new Query();
var mockedQueryTask:QueryTask = nice(QueryTask);
var mockedQueryTaskFactory:QueryTaskFactory = nice(QueryTaskFactory);
// Setup expectations
expect(mockedQueryTaskFactory.createQueryTask("http://test.com")).returns(mockedQueryTask);
expect(mockedQueryTask.execute(query, null)).once();
// Setup handlers for expected and not expected signals (events)
var queryQueue:IQueryQueue = new QueryQueue(mockedQueryTaskFactory);
handleSignal(this, queryQueue.completed, verifyOnCompleted, 500, null);
registerFailureSignal(this, queryQueue.canceled);
// Do it
queryQueue.add(query, "http://test.com");
queryQueue.execute();
// Test that things went according to plan
assertThat(queryQueue.inProgress, isTrue());
verify(mockedQueryTask);
verify(mockedQueryTaskFactory);
function verifyOnCompleted(event:SignalAsyncEvent, passThroughData:Object):void
{
assertThat(queryQueue.inProgress, isFalse());
}
}
该QueryQueue.execute
方法看起来像这样。
public function execute():void
{
_inProgress = true;
for each(var queryObject:QueryObject in _queryTasks)
{
var queryTask:QueryTask = _queryTaskFactory.createQueryTask(queryObject.url);
var asyncToken:AsyncToken = queryTask.execute(queryObject.query);
var asyncResponder:AsyncResponder = new AsyncResponder(queryTaskResultHandler, queryTaskFaultHandler, queryObject.token);
asyncToken.addResponder(asyncResponder);
}
}
private function queryTaskResultHandler(result:Object, token:Object = null):void
{
// For each result collect the data and stuff it into a result collection
// to be sent via the completed signal when all querytask responses
// have been processed.
}
private function queryTaskFaultHandler(error:FaultEvent, token:Object = null):void
{
// For each error collect the error and stuff it into an error collection
// to be sent via the completed signal when all querytask responses
// have been processed.
}
对于上面的测试#6,我想要做的是测试在queryTaskResultHandler
和中返回的数据是否queryTaskFaultHandler
被正确处理。
也就是说,completed
在所有查询响应(包括成功和失败结果)返回之前,我不会调度事件。
为了测试这个过程,我认为我需要模拟每个模拟查询任务的结果和故障处理程序中返回的数据。
那么,我如何模拟传递给通过AsyncResponder
使用 FlexUnit 和 mockolate 创建的结果处理程序的数据。