In a recent Apache Flex project, we needed to implement automated user tests. Selenium is an (open source) tool for automating your browser, but there was no modern (aka working) extension for Flex applications. We've created the open source project Flexium, both a JAVA and ActionScript extension which enables you to communicate between Selenium and Flex.
2. About me
A Belgian consultant working at
Stack & Heap.
A passionate RIA developer.
A ZEND certified PHP Engineer.
A huge fan of the Randori Framework.
3. What are we talking about?
Wikipedia says:
... test automation is the use of special
software (separate from the software being
tested) to control the execution of tests and the
comparison of actual outcomes to predicted
outcomes. Test automation can automate some
repetitive but necessary tasks in a formalized
testing process already in place, or add
additional testing that would be difficult to
perform manually ...
4. Why should you bother?
● Efficiency
● More complete error reports
● Huge time savings
● A more complete code coverage
5. Why did we bother?
While taking over an existing project
● Huge and complicated code base
● No existing unit tests
● Complaints by users:
○ a lot of bugs in the GUI
○ a lot of recurrent bugs
7. External testing tool
Selenium
A suite of tools to automate your web
browser.
External Interface
communication between your browser
and the Flash Player.
8. ● Java Test
○ Selenium for Java
○ Standalone Selenium server
○ FlexiumLink and FlashSelenium
● Flex Application
○ Flexium
https://github.com/StackAndHeap/flexium
The Selenium setup
17. ● Flexium
○ Compiles into your application
○ Parsing of your applications Stage
○ Registers your (custom) commands
Under the hood - Apache Flex (1)
18. Compiles into your application
... separate from the software being tested...
1) Use a Mixin
...
[Mixin]
public class Flexium extends Sprite {
...
Under the hood - Apache Flex (2)
19. Compiles into your application
... separate from the software being tested...
2) Include library
include-libraries library [...]
Under the hood - Apache Flex (2)
20. Parsing of your applications stage
Every component that gets added to the stage will be parsed by the
AS3-commons Stage Processing Library
http://as3commons.org/as3-commons-stageprocessing/index.html
Under the hood - Apache Flex (3)
21. Parsing of your applications stage with AS3Commons
private var _registry:FlashStageObjectProcessorRegistry;
private function initProcessor():void {
_registry = new FlashStageObjectProcessorRegistry();
_registry.useStageDestroyers = true;
_registry.registerStageObjectProcessor(
new EventDispatchingObjectProcessor(this),
new EventDispatchingObjectSelector()
);
_registry.initialize();
}
Under the hood - Apache Flex (4)
22. Parsing of your applications stage with AS3Commons
private var _registry:FlashStageObjectProcessorRegistry;
private function initProcessor():void {
_registry = new FlashStageObjectProcessorRegistry();
_registry.useStageDestroyers = true;
_registry.registerStageObjectProcessor(
new EventDispatchingObjectProcessor(this),
new EventDispatchingObjectSelector()
);
_registry.initialize();
}
Under the hood - Apache Flex (4)
23. Parsing of your applications stage with AS3Commons
private var _registry:FlashStageObjectProcessorRegistry;
private function initProcessor():void {
_registry = new FlashStageObjectProcessorRegistry();
_registry.useStageDestroyers = true;
_registry.registerStageObjectProcessor(
new EventDispatchingObjectProcessor(this),
new EventDispatchingObjectSelector()
);
_registry.initialize();
}
Under the hood - Apache Flex (4)
24. Parsing of your applications stage with AS3Commons
private var _registry:FlashStageObjectProcessorRegistry;
private function initProcessor():void {
_registry = new FlashStageObjectProcessorRegistry();
_registry.useStageDestroyers = true;
_registry.registerStageObjectProcessor(
new EventDispatchingObjectProcessor(this),
new EventDispatchingObjectSelector()
);
_registry.initialize();
}
Under the hood - Apache Flex (4)
25. Parsing of your applications stage with AS3Commons
public class EventDispatchingObjectSelector implements IObjectSelector {
public function approve(object:Object):Boolean {
return object is UIComponent;
}
}
Under the hood - Apache Flex (5)
26. Parsing of your applications stage with AS3Commons
public function process(displayObject:DisplayObject):DisplayObject {
_stageParser.addElement((displayObject as UIComponent).id, displayObject);
return displayObject;
}
public function destroy(displayObject:DisplayObject):DisplayObject {
_stageParser.removeElement((displayObject as UIComponent).id);
return displayObject;
}
Under the hood - Apache Flex (6)
27. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
28. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
29. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
30. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
31. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
32. Under the hood - Apache Flex (7)
Registers your (custom) commands
public class MouseAction extends AbstractAction implements IAction {
public function MouseAction(parser:StageParser) {
super(parser);
}
public function attachActions():void {
attach("click", doFlexClick);
}
public function doFlexClick(id:String, args:String):String {
var child:Object = parser.getElementById(id);
if (child == null) {
return Errors.OBJECT_NOT_FOUND;
}
return String(child.dispatchEvent(new MouseEvent(MouseEvent.CLICK)));
}
}
33. FYI
● working with data
○ mock data
■ same result on every test
■ same result on every system
34. What's next?
● My way, not the highway...
● Custom components - custom commands