DOWNLOAD MVC EXAMPLE WITH TESTS
DOWNLOAD SELENIUM AUTOMATION JAVA PROJECT
In this topic we will cover:
- unit testing with fluint
- integration testing with fluint
- automation testing with Selenium and TestNG
- overview of the Flex Automation API
fluint – Flex Unit and Integration Testing Framework
Based loosely on the concepts of FlexUnit and its ancestor JUnit, fluint provides enhanced asynchronous support, a graphical test runner, integration with continuous build systems and an optional Adobe AIR client for directory watching.
FLUINT HOME PAGE AT GOOGLE CODE
INTRODUCTION TO FLUINT
The repository of the project is organized in the best way I’ve seen so far in a Flex open source project. The structure is optimized for fast setup – you just need to check out a project into your workspace and you’re ready.
Unit Testing
The goal of unit testing is to verify and validate that individual pieces of code fit for use. With fluint you can do a variety of tests:
- simple assertions
- asynchronous tests (testing asynchronous communication and services)
- asynchronous test setup (waiting for creation completed before test start)
- test visual components
WRITING A FLUINT BASIC TEST
WRITING ASYNCHRONOUS TEST
USING ASYNCHRONOUS SETUP
If you download the MVC Example you’ll find the testing code in the src/test directory.
The simple assertion is demonstrated in TestStatisticsServiceRandomLinesOfCode.as
Simple asynchronous test is demonstrated in TestStatisticsServiceOperations.as
You can see an asynchronous test setup in the following test cases:
TestInitialization.as
TestFiltering.as
TestLayoutChange.as
Some Additions to fluint
Since we’re dealing with RIA we must pay a great deal of attention to the interactions. Some interactions can not be automated easily and may require human intervention. Thus we must create some sort of a hybrid between a unit test and a functional test. To initiate the assertions the tester must perform a certain interaction with the unit under test, which is usually a visual component with a complex gesture that’s difficult to automate. The unit test is still part of a test suite, but the difference is that is should not fail while waiting for the designated interaction to be performed. The current implementation of asychHandler() expects a timeout to be specified. I’ve introduced a slightly modified method that will wait for unspecified period of time:
/**
* Same as asyncHandler, but doesn't have a timeout
*/
public function waitingHandler( eventHandler:Function ):Function {
var asyncHandler:WaitingHandler = new WaitingHandler( this, eventHandler );
asyncHandler.addEventListener( WaitingHandler.EVENT_FIRED, handleAsyncEventFired, false, 0, true );
pendingAsyncCalls.push( asyncHandler );
return asyncHandler.handleEvent;
}
This method is part of the
CustomTestCase which inherits the fluint base
TestCase class. The
WaitingHandler class inherits the fluint
AsyncHandler.
In order to have visual testing I’ve modified the sample
TestRunner and extended it with a visual testing environment. You can take a look at my modifications in the
UITestRunner.as
RUN THE UI TEST RUNNER (FIRST TEST WAITS FOR THE USER TO CHECK THE CHECKBOX)
Integration Testing with fluint
After components and modules were unit tested (individually tested), the next step is to compose them into a bigger group and test the behavior of the whole group. Integration tests may be a bit more complex than unit tests. For complex test cases fluint provides us with test sequences.
READ MORE ON TESTING WITH SEQUENCES
Check out my sample test case that’s using sequences – TestLayoutChange.as
Automating fluint Unit and Integration Tests
Automation of unit and integration test is important part of a Continuous Integration build. Currently for fluint an Ant wrapper for the tool is available.
READ MORE ON CONTINUOUS INTEGRATION WITH FLUINT
Testing Flex Application with Selenium
Bad news for the QA engineers – I was able to produce only manually Selenium tests in Java for replaying a sequence of user gestures. Right now for testing Flex applications with Selenium there is only one available extension, but it works only with the old Beta 1 of the Selenium IDE when running only on Firefox 2. I haven’t tested that configuration. So currently there is no easy way for automatically recording the user gestures taken in the course of using a Flex application. And all my Selenium tests had to be written manually.
DOWNLOAD SELENIUM AUTOMATION JAVA PROJECT
For the above project you need a Selenium server and a Selenium remote control.
There are two partial solutions available for testing Flex applications with Selenium.
Selenium Flex API
As I’m writing this I see that today a new version of the API is available and the release notes for this version claim that it should work with the latest beta of Selenium IDE. I really want to check it out but for some reason the ZIP can’t be downloaded right now.
DOWNLOAD SELENIUM FLEX API
The Selenium Flex API consists of several components:
- SWC that you must import to the Flex application with the -include-library compiler switch
- JavaScript extension to the Selenium IDE, so you can record user gestures – this extension works only for Flex applications that have already included the above SWC
- Selenium Remote Control client – I bet the provided class is automatically generated with some tool – the code contained syntax errors and did not prove as working
Flash-Selenium
The flash-selenium project aims to extend the Selenium RC clients for adding Flash communication capabilities. It basically adds the capability to invoke Flash functionality through JavaScript and the ExternalInterface feature of Flash. I don’t like this approach, because you need to expose a great deal of functionality as ExternalInterface and this approach can’t be applied for black box testing.
GOOGLE CODE HOME PAGE OF FLASH-SELENIUM
My sample = Flash-Selenium + Selenium Flex API
My sample uses both the Flash-Selenium remote control client and the Selenium Flex API SWC included in the Flex project. Let’s look at the code of the test case:
@BeforeSuite
public void startSeleniumServer() throws Exception {
seleniumServer = new SeleniumServer();
seleniumServer.start();
}
This is TestNG preparation method before starting the test suite.
The following is a setup method for each test case. Please, note the way I’m using Flash-Selenium:
@BeforeTest
public void startBrowser() throws Exception {
selenium = new DefaultSelenium("localhost", 4444, "*firefox", BASE_URL);
selenium.start();
selenium.open(URL);
flexApp = new FlashSelenium(selenium, FLEX_APP);
while (flexApp.PercentLoaded() != 100) {
Thread.sleep(1000);
}
Thread.sleep(5000); // extra assurance that everything is loaded
}
Now that the Flex application is up and 100% loaded the test is ready to be run. Please, note the way I invoke functionality in the Selenium Flex API SWC through Flash-Selenium:
@Test
public void checkLayoutUpdate() throws Exception {
flexApp.call("doFlexClick", "advancedViewCheckbox", "");
Thread.sleep(5000);
String isChecked = flexApp.call("getFlexCheckBoxChecked", "advancedViewCheckbox", "");
Assert.assertEquals(isChecked, "true");
String listData = flexApp.call("getCustomLayoutListData", "#");
Assert.assertEquals(listData.split("#").length, 9);
flexApp.call("doFlexClick", "filterTextInput", "");
flexApp.call("doFlexType", "filterTextInput", "br");
Thread.sleep(5000);
listData = flexApp.call("getCustomLayoutListData", "#");
String[] items = listData.split("#");
Assert.assertEquals(items.length, 2);
Assert.assertTrue(items[0].toLowerCase().contains("br"));
Assert.assertTrue(items[1].toLowerCase().contains("br"));
flexApp.call("doFlexDoubleClick", "filterTextInput", "");
flexApp.call("doFlexType", "filterTextInput", "");
Thread.sleep(5000);
listData = flexApp.call("getCustomLayoutListData", "#");
Assert.assertEquals(listData.split("#").length, 9);
}
Notice some methods are part of the Selenium Flex API and some methods are exposed on purpose through
ExternalInterface. The following is part of the
CustomLayoutList.as:
// Methods exposed only for Selenium testing purposes:
private function initializeExternalInterface() : void
{
ExternalInterface.addCallback("getCustomLayoutListData", getCustomLayoutListData);
ExternalInterface.addCallback("getCustomLayoutListLayout", getCustomLayoutListLayout);
}
A More Cleaner Approach
A more cleaner approach would be to use the Flex Automation API:
An appropriate agent class for Selenium should be created and an appropriate JavaScript extension to the Selenium IDE.
READ MORE ABOUT THE FLEX AUTOMATION APIS
CHECK ADOBE’S AUTOMATION SAMPLE
The following illustration shows the initialization process of the SystemManager, AutomationManager and Automation objects:
And this is how the automation flow works:
Related Articles
Selenium-Flex-Tests with Maven
Flex acceptance testing and continuous integration