3

我正在 Flex 应用程序中测试一些事件调度代码,使用 FlexUnit 的addAsync方法来测试事件是否被调度。到目前为止,我可以确保至少触发了一个事件。但是,我想更详细一点;我想确保准确地发送我期望的事件集。是否有一个有用的测试模式(或者,甚至是不同的测试框架——我很灵活!)来完成这个?

我尝试了这段代码,但它似乎没有被第二次调用:

protected function expectResultPropertyChange(event: Event, numberOfEvents: int = 1): void {
    trace("Got event " + event + " on " + event.target + " with " + numberOfEvents + " traces left...");
    assertTrue(event.type == ResponseChangedEvent.RESPONSE_CHANGED);
    if (numberOfEvents > 1) {
        event.target.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, addAsync(expectResultPropertyChange, 1000, numberOfEvents - 1));
    }
}

public function testSomething(): void {
    requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, addAsync(expectResultPropertyChange, 1000, 2));
    requiredQuestion.responseSelected("1", true);
    requiredQuestion.responseSelected("2", true);
}
4

2 回答 2

2

这将是一个高级示例,说明如何使用模拟对象来解决类似的问题,无论它是在做什么异步调用。显然我看不到你的代码,所以我不能给你一个精确的例子。

因此,正如我在评论中所说,您可以模拟类中的依赖项来伪造异步调用,从而使它们变得同步。参加以下课程

public class RequiredQuestion extends EventDispatcher
{
    private var someAsynchronousObject : IAsynchronousObject;

    public function RequiredQuestion(someAsynchronousObject : IAsynchronousObject = null)
    {
        someAsynchronousObject = someAsynchronousObject || new AsynchronousObject();
        someAsynchronousObject.addEventListener(Event.COMPLETE, asyncCallComplete);
    }

    public function responseSelected(id : String, flag : Boolean) : void
    {
        //Will asynchronously fire the Event.COMPLETE event
        someAsynchronousObject.startAsynchrounsCall(); 
    }

    protected function asyncCallComplete(event : Event) : void
    {
        dispatchEvent(new ResponseChangedEvent(ResponseChangedEvent.RESPONSE_CHANGED));
    }
}

因此,默认情况下,您使用的是要使用的具体类,除非 someAsynchronousObjec 通过构造函数注入到类中。AsycnhronousObject 可能有它自己的单元测试,或者它在一个外部类中,所以你并不真正想要或需要测试它的功能。您现在可以做的是创建一个实现 IAsynchronousObject 的模拟对象,该对象可用于伪造其行为。使用 ASMock 框架,测试可能看起来像这样:

public function testSomething(): void 
{
    var mockIAsycnhronousObject :  IAsynchronousObject =
        IAsynchronousObject(mockRepository.createStrict( IAsynchronousObject));

    SetupResult.forEventDispatcher(mockIAsycnhronousObject);
    SetupResult.forCall(mockIAsycnhronousObject.startAsynchronousCall())
        .dispatchEvent(new Event(Event.COMPLETE)); // all calls to the startAsynchronousCall method and dispatch the complete event everytime it's called.

    mockRepository.replayAll();

    var requiredQuestion : RequiredQuestion = new RequiredQuestion(mockIAsycnhronousObject);

    var callCount : int = 0;
    requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, function(event : ResponseChangedEvent)
    {
        callCount++;
    });

    requiredQuestion.responseSelected("1", true);
    requiredQuestion.responseSelected("2", true);

    assertEquals(2, callCount);

    mockRepository.verifyAll();
}

这只是模拟如何帮助您进行单元测试的一个示例。尽管对于 ActionScript(12 月发布)来说仍然很新,但仍有大量关于模拟的信息。ASMock 基于 .net Rhino 模拟,因此如果您需要帮助,搜索 Rhino 模拟应该会产生更多结果。

绝对是一种不同的思维方式,但是一旦你进入它,你往往会想知道没有它们你是如何进行单元测试的。

于 2009-07-23T07:50:55.097 回答
2

回应评论...

如果事件是直接派发的呢?responseSelected 不会在复合对象上触发异步事件,它只是直接调度 RESPONSE_CHANGED 事件本身。我没有看到如何使用您的方法来模拟这种方法。请注意,我对模拟测试实践很模糊,所以我可能在这里缺少一个简单的解决方案。

..在这种情况下,您不需要使用模拟或 addAsync。这样的事情会做:

public function testSomething(): void 
{
    var requiredQuestion : RequiredQuestion = new RequiredQuestion();

    var callCount : int = 0;
    requiredQuestion.addEventListener(ResponseChangedEvent.RESPONSE_CHANGED, function(event : ResponseChangedEvent)
    {
        callCount++;
    });

    requiredQuestion.responseSelected("1", true);
    requiredQuestion.responseSelected("2", true);

    assertEquals(2, callCount);
}
于 2009-07-23T15:53:50.777 回答