Lifes too short – write fast code!

nadeem.shabir | | Thursday, March 19th, 2009

ABSTRACT

This is the second talk that follows-up on the 14 best practices from YSlow and “High Performance Web Sites”. The first talk presented three new best practices: Split the Initial Payload, Load Scripts Without Blocking, and Don’t Scatter Inline Scripts.

The most important of these is loading external scripts without blocking other downloads and preventing page rendering. One complication is this may introduce undefined symbol errors if inlined code uses symbols from the external scripts. Luckily, there are several techniques to workaround this problem. That and other topics will be covered in this presentation of three more best practices:

* Coupling Asynchronous Scripts
* Use Iframes Sparingly
* Flush the Document Early

Much of this talk discusses material from Steve’s book, High Performance Websites: Essential Knowledge for Front-End Engineers. The talk is full of great advice, I found the discussion around loading scripts both synchronously and asynchronously and the performance gains that can be achieved. However this has to be combing with understanding that you also have to couple scripts together in order to preserver the order they are loaded in, as well as understanding that by default loading external scripts blocks download of other elements on the page. Steve discusses a number of techniques that can address these issues as well as the pros and cons associated with each. His discussion around John Resigs idea of using degrading script tags is extremely useful.

This is a hugely useful tech talk and a must for anyone doing serious Javascript development.

Why PHP Won

nadeem.shabir | | Wednesday, January 21st, 2009

An excellent article by Eric Reis over on his blog in which he talks about “why PHP won” in his web application development over other (web scripting) languages:

As a language, it’s inelegant. Its object-orientation support is “much improved” – which is another way of saying it’s been horrendous for a long time. Writing unit tests or mock objects in PHP is an exercise in constant frustration. And yet I keep returning to PHP as a development platform, as have most of my fellow startup CTOs. This post is about why.

Its an interesting piece in which Eric chooses to describe PHP’s success in terms of what a new language might have to do better in order to challenge PHP’s popularity/success, in short he suggests the following:

  • Speed of iteration (a good write/test/debug cycle)
  • Better mapping of outputs to inputs
  • A similar standard library
  • A better OOP implementation

I have to confess I found myself agreeing with Eric. His piece is well worth reading!

Geppeto: Consumer’s Approach to Programming

nadeem.shabir | | Saturday, November 15th, 2008

ABSTRACT

Contemporary society is experiencing a steady stream of new electronic gadgets, software products, and web applications. In this flood of functionality, users have adapted to rely less on manuals (if they are present at all) and shift their learning to trial and error, common paradigms, and experimentation. To accommodate this style of use — or perhaps driving this behavior – developers have successfully abstracted much of the technological complexity and transformed it into intuitive user interfaces often avoiding the need for reading lengthy manuals and formal training. Is it possible to adopt the same trial-and-error experimentation habit not only for using gadgets, but also for application development? We claim that intuitive aggregation and combination of software gadgets makes this possible.

In this talk, we will show the use of current technology in building a consumer oriented development tool appropriate for individuals not formally trained in programming. We demonstrate that the complexity of existing system and scripting languages i.e.; syntax, semantics, control and data flow, data structures, data types, and programming components can be successfully replaced with analogies intuitively accessible to a much wider consumer population based exclusively on their use and understanding of user interfaces in popular web applications. We present a demo of Geppeto — a consumer tool for gadget-based application development. Composing gadgets with Geppeto does not require programming experience or reading of convoluted manuals. The presented research is sponsored by Google Inc. and the Croatian Ministry of Science.

Test-Driven JavaScript Development with JsUnit

nadeem.shabir | | Saturday, September 20th, 2008

The last time I used JsUnit was when I first joined Talis. At the time my colleague Ian Davis asked me to write a JavaScript client library for one of our platform API’s to make it easy for developers to perform bibliographic searches. It wasn’t a particularly difficult task and I did it relatively easily. It was around the same time that Rob was extolling the virtues of Test Driven Development to me, and to try to prove his point we agreed to do an experiment: he asked me to set aside the library I had written and to see if I could develop the library again using test driven development. It meant I had to figure out how to unit test JavaScript, and thats when I found JsUnit. I did the exercise again and even I was impressed with the results. By having to think about the tests first, and design the interface to the library as I wrote each test it evolved very differently to my original solution. Consequently it was also far superior.

Anyway fast forward two and half years and I find myself in a similar situation. We have only just begun to start writing bits of JavaScript code based around prototype.js to help us create richer user experiences in our products if we detect that JavaScript is enabled in the browser. This now means I want to ensure that we are using the same rigour when writing these bits of code as we do in all other parts of the application – just because its JavaScript and executed inside the browser this doesn’t mean it shouldn’t be tested.

I’ve just spent the morning getting JsUnit installed and figuring out how to get it to run as part of a continuous integration process, as well as thinking about how to write tests for some slightly different scenarios. Here’s what I’ve discovered today:

Installing JsUnit

Couldn’t be easier … go to www.jsunit.net and download the latest distribution, and extract into a folder on your system somewhere, lets say
/jsunit for now. The distribution contains both the standard test runner as well as jsunit server which you will need it if you want to hook it into an ant build.

Writing Tests

In JsUnit we place our tests in a HTML Test Page which is the equivalent of a Test Class, this test page must have a script reference to the jsUnitCore.js so the test runner knows its a test. So lets work through a simple example. Let’s say we want to write a function that returns the result of adding two parameters together. The Test Page for this might look like this:

  1.  
  2. <html>
  3.  <head>
  4.   <title>Test Page for add(value1, value2)</title>
  5.   <script language="javascript" src="/jsunit/app/jsUnitCore.js"></script>
  6.   <script language="javascript" src="scripts/addValues.js"></script>
  7.  </head>
  8.  <body>
  9.     <script language="javascript">
  10.     function testAddWithTwoValidArguments() {
  11.         assertEquals("2 add 3 is 5", 5, add(2,3) );
  12.     }
  13.   </script>
  14.  </body>
  15. </html>
  16.  

For now lets save this file to /my-jsunit-tests/addTest.html

To run the test you need to point your browser at the following local url:

file:///jsunit/testRunner.html?testPage=/my-jsunit-tests/addTest.html

The test will not run since we haven’t defined the add function. Let’s do that (very crudely):

  1.  
  2. function add(param1, param2)
  3. {
  4.     return param1 + param2;
  5. }
  6.  

Now if you go to that URL it will run the test and report that it passed. Excellent, we’ve written a simple test in JavaScript. Now lets extend this a little, lets say I want to write something more complicated like a piece of JavaScript that uses Prototype.js to update the DOM of a page. Is this possible? Can I do that test first? It turns out that you can …

Lets say we have a div on the page called ‘tableOfContents’ and we want to use Prototype.js to dynamically inject a link onto the page that says [show] and lets say we want to write a function that will toggle this link to say [hide] when the user clicks on it, this link will also set the visible state of the table of contents itself which for now we’ll say is just an ordered list (OL). Our test page is going to be slightly more complex …

  1.  
  2. <html>
  3.  <head>
  4.   <title>Test Page for multiplyAndAddFive(value1, value2)</title>
  5.   <script language="javascript" src="/jsunit/app/jsUnitCore.js"></script>
  6.   <script language="javascript" src="scripts/prototype/prototype-1.6.0.2.js"></script>
  7.   <script language="javascript" src="scripts/tableOfContents.js"></script>
  8.  </head>
  9.  <body>
  10.     <div id="tableOfContents">
  11.     <h2 id="tableOfContentsHeader">Table of contents</h2>
  12.     <ol id="list-toc">
  13.     </ol>
  14.     </div>    
  15.     <script language="javascript">
  16.     function testTOC()
  17.     {
  18.         var title = $(‘lnkToggleTOC’).title;
  19.         assertEquals("should be Show the table of contents", "Show the table of contents", title);
  20.        
  21.         toggleTableOfContents();
  22.        
  23.         var title = $(‘lnkToggleTOC’).title;
  24.         assertEquals("should be Hide the table of contents", "Hide the table of contents", title);
  25.                    
  26.     }
  27.   </script>
  28.  </body>
  29. </html>
  30.  

There are some differences in this test. Firstly the html contains some markup, that I’m using as the containers for my table of contents. The table of contents has a header and the contents in the form of an empty ordered list. Now I know that I want the javascript to execute when the page is loaded, so I’ve written this test to assume that the script will run and will inject and element called ‘linkToggleToc’ which is the show/hide link next to the heading. Therefore the first line of the test uses prototype.js element selector notation to set a local variable called title to the value of the title of the element that has the id ‘linkToggleToc’. If the script failes to execute then this element will not be present and the subsequent assert will fail. If the assert succeeds, then we call the toggleTableOfContents function and then repeat the same evaluation only now we are checking to see if the link has been changed.

The code for tableOfContents.js is as follows:

  1. Event.observe(window, ‘load’, injectTOCLinks);
  2.  
  3. var titleShowTOC = ‘Show the table of contents’;
  4. var titleHideTOC = ‘Hide the table of contents’;
  5.  
  6. function injectTOCLinks()
  7. {
  8.     $(‘list-toc’).hide();
  9.     $(‘tableOfContentsHeader’).style.display = ‘inline’;
  10.    
  11.        
  12.     var elShowHideLink = new Element(‘a’, { ‘id’: ‘lnkToggleTOC’, ‘href’: ‘javascript:toggleTableOfContents()’, ‘title’: titleShowTOC, ‘class’: ‘ctr’ }).update("[show]");
  13.    
  14.     $(‘tableOfContentsHeader’).insert({‘after’:elShowHideLink});
  15. }
  16.  
  17. function toggleTableOfContents()
  18. {
  19.     var toc = $(‘list-toc’);
  20.    
  21.     if (toc.visible())
  22.     {
  23.         toc.hide();
  24.         $(‘lnkToggleTOC’).update(‘[show]‘);
  25.         $(‘lnkToggleTOC’).title = titleShowTOC;
  26.     }
  27.     else
  28.     {
  29.         toc.show();
  30.         $(‘lnkToggleTOC’).update(‘[hide]‘);
  31.         $(‘lnkToggleTOC’).title = titleHideTOC;
  32.     }
  33. }

Now if we run this test in the same way we executed the previous test it will pass. I accept that this example is a bit contrived since I know it already works and I’ve skimmed over some of the details around it. The point I’m trying to make though is that you can write unit tests for pretty much any kind of JavaScript you need to write, even tests for scripts that do dom manipulation, or make AjaxRequests etc.

Setting up the JsUnit server so you can run it in a build

JsUnit ships with its own ant build file that requires some additional configuration before you can run the server. The top of the build file contains a number of properties that need to be set, here’s what you set them to ( using the paths that I’ve been using in the above example)

  1.  
  2. <project name="JsUnit" default="create_distribution" basedir=".">
  3.  
  4.   <property
  5.     name="browserFileNames"
  6.     value="/usr/bin/firefox-2" />
  7.  
  8.   <property
  9.     id="closeBrowsersAfterTestRuns"
  10.     name="closeBrowsersAfterTestRuns"
  11.     value="false" />
  12.  
  13.   <property
  14.     id="ignoreUnresponsiveRemoteMachines"
  15.     name="ignoreUnresponsiveRemoteMachines"
  16.     value="true" />
  17.  
  18.   <property
  19.     id="logsDirectory"
  20.     name="logsDirectory"
  21.     value="/my-jsunit-tests/results/" />
  22.  
  23.   <property
  24.     id="port"
  25.     name="port"
  26.     value="9001"  />
  27.  
  28.   <property
  29.     id="remoteMachineURLs"
  30.     name="remoteMachineURLs"
  31.     value="" />
  32.  
  33.   <property
  34.     id="timeoutSeconds"
  35.     name="timeoutSeconds"
  36.     value="60" />
  37.  
  38.   <property
  39.     id="url"
  40.     name="url"
  41.     value="file:///jsunit/testRunner.html?testPage=/my-jsunit-tests/tocTest.html" />
  42. </project>
  43.  

You can then type the following command in the root of the jsunit distribution to launch the jsunit server, executes the test, and outputs a test results log file, formatted just like JUnit, and reports that the build was either successful or not if the test fails.

  ant standalone_test

Remember that in this example I’ve used a simple Test Page, however JsUnit, like any XUnit framework allows you to specify Test Suites, which is how you would run multiple Test Pages. Also the parameters in the build file woudn’t be hardcoded in you continuous integration process but would rather be passed in, and you would want to call it from your projects main ant build file … all of which is pretty simple to configure, once you know what is you want to do and what’s possible.

A possible future of Software Development

nadeem.shabir | | Monday, May 26th, 2008

This talk begins with an overview of software development at Adobe and a look at industry trends towards systems built around object oriented frameworks; why they “work”, and why they ultimately fail to deliver quality, scalable, software. We’ll look at a possible alternative to this future, combining generic programming with declarative programming to build high quality, scalable systems.

… a very interesting talk, that raises some important questions, about the very nature of software development.

Processing.js

nadeem.shabir | | Saturday, May 10th, 2008

Processing is a Open Source data visualization programming language. I first played around with it about a year ago. I was recently reminded of it by Rob, and have started playing with it again. However, I just discovered that earlier in the week John Resig released his JavaScript Port, Processing.js. So far it looks amazing, virtually all the demo/example applications that are shipped with Processing are running using the CanvasElement in JavaScript. I’m going to have a lot of fun with this.

John deserves a huge amount of credit for this contribution.

Flare: Visualization on the Web

nadeem.shabir | | Monday, October 29th, 2007

Came across Flare today and am thinking it might be very useful for some data visualisation work I’m doing, here’s the blurb:

Flare is a collection of ActionScript 3 classes for building a wide variety of interactive visualizations. For example, flare can be used to build basic charts, complex animations, network diagrams, treemaps, and more. Flare is written in the ActionScript 3 programming language and can be used to build visualizations that run on the web in the Adobe Flash Player. Flare applications can be built using the free Adobe Flex SDK or Adobe’s Flex Builder IDE. Flare is based on prefuse, a full-featured visualization toolkit written in Java. Flare is open source software licensed under the terms of the BSD license, and can be freely used for both commercial and non-commercial purposes.

Try out the online demo here.

Holding a Program in One’s Head

nadeem.shabir | | Saturday, August 25th, 2007

from an excellent new essay by Paul Graham

Good programmers manage to get a lot done anyway. But often it requires practically an act of rebellion against the organizations that employ them. Perhaps it will help to understand that the way programmers behave is driven by the demands of the work they do. It’s not because they’re irresponsible that they work in long binges during which they blow off all other obligations, plunge straight into programming instead of writing specs first, and rewrite code that already works. It’s not because they’re unfriendly that they prefer to work alone, or growl at people who pop their head in the door to say hello. This apparently random collection of annoying habits has a single explanation: the power of holding a program in one’s head.


Whether or not understanding this can help large organizations, it can certainly help their competitors. The weakest point in big companies is that they don’t let individual programmers do great work. So if you’re a little startup, this is the place to attack them. Take on the kind of problems that have to be solved in one big brain.

so very true … !

Best practises in JavaScript library design

nadeem.shabir | | Friday, August 24th, 2007

This is a very useful tech talk by John Resig, that explores a number of techniques used to build robust, reusable cross-platform JavaScript libraries.

John offers some excellent advise and whilst some if it might seem obvious it’s worrying how many existing API’s fall into some of the common pitfalls he describes.

John argues that part of writing good solid API’s is to keep the code orthogonal by ensuring that whenever you perform an action on an object that action should be consistent across all objects. In other words each object should expose the same methods, i.e. add(), remove(), all(), … etc. this creates familiarity and developers using the API know that different objects that are responsible for different things can all be used consistently.

John also makes the obvious and profound point that when creating an API you should Fear adding methods, the reason being that every method that you write is one that you will have to maintain. In fact you should try to embrace the idea that removing unused code is a good thing. It reduces the size of your API, makes it easier to learn and easier to maintain.

Going back to consistency its imperative that we use good naming conventions and naming schemes and stick with them, this also means you have to be very diligent about argument position in method calls … I know how frustrating it is when you use some of the string processing methods in PHP but the argument order changes it’s annoying!

John goes onto offer much more advice on encapsulation, functional programming, compression of libraries using Dojo. He advocates Test Driven Development for API design which generally results in better API design.

It’s an excellent talk and well worth watching for anyone who working on building JavaScript, or indeed any kind of API.

Automated regression testing and CI with Selenium PHP

nadeem.shabir | | Saturday, August 11th, 2007

I’ve been doing some work this iteration on getting Selenium RC integrated into our build process so we can run a suite of automated functional regression tests against our application on each build. The application I’m working on is written in PHP, normally when you use Selenium IDE to record a test script it saves it as a HTML file.

For example a simple test script that goes to Google and verifies that the text “Search:” is present on the screen and the title of the page is “iGoogle” looks like this:

  1.  
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  5. <title>New Test</title>
  6. </head>
  7. <body>
  8. <table cellpadding="1" cellspacing="1" border="1">
  9. <thead>
  10. <tr><td rowspan="1" colspan="3">New Test</td></tr>
  11. </thead><tbody>
  12. <tr>
  13.     <td>open</td>
  14.     <td>/ig?hl=en</td>
  15.     <td></td>
  16. </tr>
  17. <tr>
  18.     <td>verifyTextPresent</td>
  19.     <td>Search:</td>
  20.     <td></td>
  21. </tr>
  22. <tr>
  23.     <td>assertTitle</td>
  24.     <td>iGoogle</td>
  25.     <td></td>
  26. </tr>
  27.  
  28. </tbody></table>
  29. </body>
  30. </html>
  31.  

You can choose to export the script in several other languages, including PHP, in which case the test script it produces looks like this:

  1.  
  2. <?php
  3. require_once ‘Testing/Selenium.php’;
  4. require_once ‘PHPUnit/Framework/TestCase.php’;
  5.  
  6. class Example extends PHPUnit_Framework_TestCase
  7. {
  8.   function setUp()
  9.   {
  10.     $this->verificationErrors = array();
  11.     $this->selenium = new Testing_Selenium("*firefox", "http://localhost:4444/");
  12.     $result = $this->selenium->start();
  13.   }
  14.  
  15.   function tearDown()
  16.   {
  17.     $this->selenium->stop();
  18.   }
  19.  
  20.   function testMyTestCase()
  21.   {
  22.     $this->selenium->open("/ig?hl=en");
  23.     try
  24.     {
  25.       $this->assertTrue($this->selenium->isTextPresent("Search:"));
  26.     }
  27.     catch (PHPUnit_Framework_AssertionFailedError $e)
  28.     {
  29.       array_push($this->verificationErrors, $e->toString());
  30.     }
  31.     try
  32.     {  
  33.       $this->assertEquals("iGoogle", $this->selenium->getTitle());
  34.     }
  35.     catch (PHPUnit_Framework_AssertionFailedError $e)
  36.     {
  37.       array_push($this->verificationErrors, $e->toString());
  38.     }
  39.   }
  40. }
  41. ?>
  42.  

The Export produces a valid PHPUnit test case that uses the Selenium PHP Client Driver(Selenium.php). Whilst the script is valid and will run you do need add a little more to it before the test will correctly report errors. As it stands all errors captured during the test are added to an array called verificationErrors, by catching the assertion Exceptions that are thrown when an assert fails, in other words if you ran this test as it is, and it did fail you wouldn’t know! To correct this we need to do two things. Firstly, each assert needs to have a message added to it which will printed out in the test report if the assert fails. Secondly we need to modify the tearDown method so that once a test has run, it checks the verificationErrors array, and if any failures have occurred, fails the test. After making these changes the PHP test script looks like this:

  1.  
  2. <?php
  3. require_once ‘Testing/Selenium.php’;
  4. require_once ‘PHPUnit/Framework/TestCase.php’;
  5.  
  6. class GoogleHomePageTest extends PHPUnit_Framework_TestCase
  7. {
  8.   function setUp()
  9.   {
  10.     $this->verificationErrors = array();
  11.     $this->selenium = new Testing_Selenium(
  12.                          "*firefox",
  13.                          "http://localhost:4444/"
  14.                       );
  15.     $result = $this->selenium->start();
  16.   }
  17.  
  18.   function tearDown()
  19.   {
  20.     $this->selenium->stop();
  21.     if(count($this->verificationErrors) > 0 )
  22.     {
  23.        echo "VERIFICATION ERRORS:" . count($this->verificationErrors);
  24.        $this->fail(implode("\n",$this->verificationErrors));
  25.     }
  26.   }
  27.  
  28.   function testGoogleHomePage()
  29.   {
  30.     $this->selenium->open("/ig?hl=en");
  31.     try
  32.     {
  33.       $this->assertTrue(
  34.                $this->selenium->isTextPresent("Search:"),
  35.                "The string Search: was not found"
  36.       );
  37.     }
  38.     catch (PHPUnit_Framework_AssertionFailedError $e)
  39.     {
  40.       array_push($this->verificationErrors, $e->toString());
  41.     }
  42.     try
  43.     {  
  44.       $this->assertEquals(
  45.                    "iGoogle",
  46.                    $this->selenium->getTitle(),
  47.                    "The page title did not match iGoogle."
  48.       );
  49.     }
  50.     catch (PHPUnit_Framework_AssertionFailedError $e)
  51.     {
  52.       array_push($this->verificationErrors, $e->toString());
  53.     }
  54.   }
  55. }
  56. ?>
  57.  

Obviously, I have also given the PHP Class and test function slightly more meaningful names. Now you have a PHP Unit Test case that will use the Selenium PHP Client Driver with Selenium Remote Control to launch a browser, go to the specified URL, and test a couple of assertions. If any of those assertions fail, the tearDown method fails the test … pretty cool, right?

Well now it get’s better. Because the Selenium Client Driver has a published api which is pretty easy to follow, there’s no reason why you can’t just write test cases without using Selenium IDE … for those who want to you could even incorporate this into a TDD process. But for all this to hang together we need to be able to run a build, on a Continuous Integration server which checks out the code, runs unit tests and selenium regression tests against that code line, and only if all tests succeed passes the build.

We are currently using ANT, and CruiseControl to handle our CI/Automated build process. When running the automated suite of tests we need to ensure that the Selenium Remote Control server is also running which creates some complications. The Selenium Remote Control server takes several arguments which can also include the location of a test suite of html based selenium tests – which is really nice because the server will start, execute those tests and then end. Unfortunately you can’t invoke the server and pass it the location of a PHP based test suite. This means you need to find a way to start up the server, then run your tests, and once they are complete, shut the selenium server down.

He are the ANT targets that I have written to achieve this, if anyone can think of better ways of doing this I’d welcome any feedback or suggestions, to run this example you’d simply enter the command “ant selenium” :

  1.  
  2. <target name="selenium" depends="clean, init" description="Run the Selenium tests">
  3.   <parallel>
  4.     <antcall target="StartRCServer" />
  5.     <antcall target="RunSeleniumTests" />
  6.   </parallel>
  7. </target>
  8.                
  9. <target name="StartRCServer" description="Start the Selenium RC server">
  10.   <java jar="dependencies/SeleniumRC/lib/selenium-server.jar"
  11.         fork="true" failonerror="true">
  12.     <jvmarg value="-Dhttp.proxyHost=host.domain.com"/>
  13.     <jvmarg value="-Dhttp.proxyPort=80"/>
  14.   </java>
  15. </target>
  16.    
  17. <target name="RunSeleniumTests" description="RunAllSeleniumTests">    
  18.   <sleep milliseconds="2000" />
  19.   <echo message="======================================" />
  20.   <echo message="Running Selenium Regression Test Suite" />
  21.   <echo message="======================================" />
  22.   <exec executable="php"
  23.        failonerror="false"
  24.        dir="test/seleniumtests/regressiontests/"
  25.        resultproperty="regError">
  26.        <arg line="../../../dependencies/PHPUnit/TextUI/Command.php –log-xml ../../../doc/SeleniumTestReports/RegressionTests/TestReport.xml AllRegressionTests" />
  27.   </exec>
  28.   <get taskname="selenium-shutdown"
  29.     src="http://localhost:4444/selenium-server/driver/?cmd=shutDown"
  30.     dest="result.txt" ignoreerrors="true" />
  31.                    
  32.   <condition property="regressionTest.err">
  33.     <or>
  34.        <equals arg1="1" arg2="${regError}" />
  35.        <equals arg1="2" arg2="${regError}" />
  36.     </or>
  37.   </condition>
  38.  
  39.   <fail if="regressionTest.err" message="ERROR: Selenium Regression Tests Failed" />               
  40. </target>
  41.  

A couple of notes, the reason I have to use a conditional check at the end of the selenium target is because, if the exec task that runs the PHP tests was set to failonerror=true then the build would never reach the next line which shuts the Selenium RC server down. To ensure that always happens I have to set the exec to failonerror=false, but this means I have to check what the result was from the exec. Which if successful will return 0, if test failures exist will return 1, and if there were any errors (preventing a test to be exectuted ) will return 2. Hence the conditional check sets regressionTest.err if either of these latter two conditions are true.

Also in order to start up the server, which could take up to a second, but can’t be sure precisely how long. I have to use the Ant Parallel task, which calls the task to start the server and the task to run the tests at the same time. The task to run the tests has a 2 second sleep in it, which should be more than enough time to allow the server to start. This all kind of feels a little clunky, but at the moment it does work very well.

In a nutshell, thats how you integrate PHP based Automated Selenium Regression tests into a continuous build.

Next Page »

Powered by WordPress | Theme by Roy Tanck