Wednesday 15 January 2014

Functional Testing Starling Applications with Cucumber and Melomel Redux - Part 2

Command Line Building

In my last post (http://ttmmhe.blogspot.co.uk/2014/01/functional-testing-starling.html) I discussed the pains of not taking a test first approach to building applications.  One of the core pieces to be successful in feature based development is to be able to consistently build and test your application, this means being able to build it almost anywhere and run your tests without the need for a developer to run the build an army of testers to manually click through it.

The first step to this is to get a build script running which could be executed on by your continuous integration server.

Thankfully there are a number of handy tools out there which you can use to create your build scripts, Ant, Maven, Gradle, Bash, Rake to name but a few, my personal preference is Rake which is ruby based, mainly as it integrates well with lots of other Ruby packages which use for testing and also its quite simple to write.

For this example I am going to use Rake and the Ruby gem ASRake which handles all our compiler commands very nicely.  It is not the purpose of this tutorial to go into the depths of Rake, the internet has many far better than I could write.

We are going to compile the demo which comes with the Starling download, other than changing a few file paths I have not modified the code at all.  All source for this example can be found at:

https://github.com/nicholasjackson/melomel_starling_example

The context of this assumes that you are using a mac or linux environment if you are using windows you will need to change the paths from / to \ however everything should still work.

Flex SDK

You are going to need a Flex SDK, I am currently using the Apache SDK 4.11 you can download this from http://flex.apache.org/ this will also install the Air SDK if you select it as an option.

ASRake requires that you set the environment variable for FLEX_HOME you can set this by executing the terminal command:
"export FLEX_HOME=/path/to/your/sdk"

Rakefile

For our build we have a few dependancies:
Ruby
ruby gem :- asrake
ruby gem :- zip

My personal preference is to use RVM (http://rvm.io/) to manage my Ruby installs and gemsets, the two files .ruby-gemset and .ruby-version let RVM know which gemset repository and version of ruby you would like to use.  Think of gemsets like workspaces, you can install all sorts of gems but they are local to that gem set so if you are working on a different project which has different dependancies there is no conflict.

There is also a file called Gemfile the contents of this are....

source 'https://rubygems.org' 

gem "cucumber", "~> 0.10.0"
gem "asrake", "~> 0.14.1"
gem "zip", "~> 2.0.2"
gem "rspec", "~> 2.14.1"

This file is used by the Ruby bundler command which will download and install the gems from the repository rubygems.org and install them for use in your gemset.  Currently we only need asrake and zip for this part of the process but it will not hurt to install the others.

From your command line execute 
"bundle"

If your system complains you do not have bundler then you may have to install it with "gem install bundler".

Now lets look at our Rakefile, at the top of the file we are defining our ASRake setup:

args = ASRake::Mxmlc.new "bin/Demo_Mobile.swf"
args.file_specs = 'src/Demo_Mobile.as'
args.target_player = 11.9
args.debug = true
args.source_path << "src"
args.library_path << "libs"
#args.external_library_path << "air/nativelibs/NativeGATracker-v2.0.4.ane"
#args.external_library_path << "air/nativelibs/NativeExtension.ane"
args.isAIR = true

current = Dir.pwd
unzipDir = "#{current}/unzippedane"

I'm going to run through this line by line but this is going to do our build.

# Create a new instance of as rake and specify the output directory for our compile binary, in this case the bin folder and Demo_Mobile.swf as a filename.
args = ASRake::Mxmlc.new "bin/Demo_Mobile.swf" 

# This line defines the path to our applications main class.
args.file_specs = 'src/Demo_Mobile.as'

# The version of player you wish to target.
args.target_player = 11.9

# Set to true to enable debug mode, false for your release builds.
args.debug = true

# Set your source path, if you have multiple source paths you can just add this line multiple times with your difference source paths.
args.source_path << "src"

# Set your library paths if you are using any pre-compiled libraries, again this can be set multiple times if you have more than one library path.
args.library_path << "libs"

# This line is commented out for our example as we are not using any native extensions however if you are then you add them like so.
#args.external_library_path << "air/nativelibs/NativeGATracker-v2.0.4.ane"

# We tell the compiler we are going to build an adobe air app
args.isAIR = true

# Set a variable to the current working directory
current = Dir.pwd

# Specify the directory to which we would unzip any ANE files should we have any
unzipDir = "#{current}/unzippedane"

Full details about the package can be found on the Github read me: (https://github.com/nexussays/ASRake)

Build Task

task :build => [args,:unzipane] do 
cp_u "src/Demo_Mobile-app.xml", "bin/"
Dir.glob("assets/*") do |folder|
cp_r folder, "bin/"
end
end

In the definition of this task the => arrow signifies that the task has a dependancy on other tasks, in this case args which is our ASRake build and unzipane which would unzip any native extension so that they can be picked up by the debugger.

By simply making a dependancy on the ASRake builder Rake will automatically invoke the execute method of args, sometimes you may only want to build your application and therefore your task would be nice an neat however in this instance we need to copy some assets which are loaded at runtime by the app.

I am not going to examine the :unzipane task as we are not using it in this example, its just there for reference should you need this.  If I get the time I will fork ASRake and add unzipping native extensions and running the build as rake tasks removing all this ugly code.

Build Our Code

This is the complex part, actually its not really all you have to do is type 
"rake build"

Hopefully you do not have an error message and you are now good to run the application.

Run the Application

I have created a rake task called run to start the Air Debug Launcher, the full settings and help can be found here (http://help.adobe.com/en_US/air/build/WSfffb011ac560372f-6fa6d7e0128cca93d31-8000.html).

The below code executes a shell command which starts the ADL.  The ADL requires certain parameters such as profile (mobile, desktop), screensize (predefined such as iPhone or custom), platform and a path to your application config xml file.  This file contains details such as the swf to start and various settings for the runtime.  Its exactly the same code that IntelliJ or Flash builder would generate for you.

flex = ENV["FLEX_HOME"]
sh "#{flex}/bin/adl -extdir #{unzipDir} -profile extendedMobileDevice -screensize iPhone -XversionPlatform IOS #{current}/bin/Demo_Mobile-app.xml"

To run the app all we have to do is execute the task run like so:
"rake run"

In our rake file you can see that run has a dependancy of build so all the build tasks would be executed before the ADL is started, this is mainly because I generally change code and forget to build then spend ages working out why my bug is still there.  If you just want run to run then remove => :build.

Hopefully now you will have the Starling demo running, the next part is to look at Melomel and how we can use it for our functional testing.




Source Download



Tuesday 14 January 2014

Functional Testing Starling Applications with Cucumber and Melomel Redux - Part 1

Background


A few months ago we decided to embark on a cross platform application for our store staff, there were three criteria which the application must meet:

1. It must be fun.
2. It must be cross platform.
3. It must be fun.

After spending some time thinking about what we wanted to do we realised that we wanted the app to feel like a game. We then had the harsh realisation that this was not going to be easy to code, in fact after running up some rough estimates of effort we realised that it was also going to be expensive to build native.

We did some research and concluded that HTML5 would not give the performance we wanted from animation on mobile platforms and that we did not really want to use Unity.   Having read a lot about Starling and the amazing cross platform performance we decided we would give this a go and started to build our stack around the Starling framework.  Both Keith and I used to be Flash programmers back in the day when Flash was still owned by Macromedia and both of us have a warm place in our hearts for ActionScript so coding in Starling should not be too alien.  Zan an Android developer who we had just recruited stupidly expressed interest in the project and having no past experience in either ActionScript or Flash was thrown straight into the deep end.  Alex an epic JavaScript developer who saw trouble a mile away was press ganged onto the project and we had our merry band.

One of the things we have been concentrating on at Marks and Spencer has been solid engineering principles, we have spend a lot of time working on Agile practices, Continuous Integration, TDD and BDD using cucumber.  Personally I have bored myself silly telling the developers about the virtues of Test First Development, how important CI is, etc, etc.

When we were putting together our stack for the app we decided that we would use Starling but we would also implement the Pure MVC framework to give us clean separation and testability.  We would write everything full TDD and we would have full automated functional testing.

Tech spike time and it did not go well, due to inexperience we battled with flex unit so dropped it, we could not work out how to test the Pure MVC components in isolation so we didn't, we could not find a functional testing frame work so we decided that our poor automation tester Anu would manually test the app, she still hates us and I don't blame her.

So in effect we decided to do everything that modern development methodology tells you not to and funnily enough we ended up in exactly the same mess that conventional test driven development is intended to avoid.

Post delivery of the app which was not a great success due to a large number of defects, these were eventually fixed but we realised that we could not continue developing in this way and had to either:

1. Change core technology to something which we can write tests for.
2. Write some testing frameworks.

We chose 2, mainly because I like Starling, and secondly because I refuse to admit I was wrong about choosing it in the first place.

Now Paul who works for us used to work for the BBC building their iPlayer application in Flex, he suggested we look at a framework called Melomel written by Ben Johnson (https://github.com/benbjohnson/melomel).  I took a look and it is indeed a very impressive framework however incompatibility between flash.display.DisplayObject and  starling.display.DisplayObject meant we could not use it.

Unless we modified it.

So we did (https://github.com/DigitalInnovation/melomel).

Melomel had not been touched for a couple of years and needed a little love so we abstracted out DisplayObject and its descendants into a common interface, modified all the tests, wrote implementations for starling objects, wrote a whole heap more tests added touch and swipe functionality and ended up with a rather nice Cucumber framework that allows us to interrogate and interact with our Starling applications.

In part two I am going to show you how to build and launch your application using a Rake not an IDE and get your initial cucumber framework setup.