Saturday, October 30, 2010

How to run selenium tests as part of maven build phase

Recently I came across a very simple requirement.  Our project used Maven as the build tool and we wanted to run Selenium tests as part of the build.  The idea was, QA's write the automated selenium tests, these should run as part of the integration-test build phase

There are multiple advantages of doing this:
  • We could run these Selenium tests on our Continuous Integration server (Hudson in our case) as part of build process.  This means, if because of some check-in, a selenium tests fails, the build fails and hence someone has to fix it!
  • Developers and QA's can easily run these functional tests whenever they want.  For e.g. if developers want to make sure that the code they are about to checkin does not break any existing functionality they can run the functional tests before checkin with just one command.
So how do they do it?

Lets try and reverse engineer the problem.  To run selenium tests we need to do the following things
  1. Compile the app
  2. Run unit-tests
  3. Create a war file of the application
  4. Run an tomcat server (or any other servlet container you are using)
  5. Deploy the war file created in step 3 on the server started in step 4
  6. Start the selenium server
  7. Fire the selenium tests
Looks like a lot of work to me!  But don't worry we will see in a moment that its not as difficult as it sounds.

Lets do this step-by-step:

Lets break down the problem.  If you look at the above mentioned 7 steps.  We can classify them in four broad categories
  1. Compile the application and package it as a war file. (steps 1-3)
  2. Run the tomcat server (steps 4-5)
  3. Run the selenium server (step 6)
  4. Run the selenium tests (steps 7-8)   
Problem looks simpler now?  Lets try and slove the above four problems separately first.  Later  we will see how we can solve all of them using just one command.

Solving the step 1:

Assuming that you already have the pom.xml setup to properly compile and run unit-tests.  We need to add the configuration in pom.xml to package the application as war file.  This is what we have to do

Find the tag called <packaging> in pom.xml and set the value of the tag to war instead of jar.

Then, we need to tell maven about how the war file will be generated.  This is done using the maven-war-plugin.  The sample configuration looks like this:

Of course for all this to work you should have a proper directory structure and web.xml.  But I will assume that you already have that in place.

At this point if you run the following command:

You will get a war file ready to be deployed in any servlet container.

Next, Solving the step 2:

To run an embedded tomcat server we have to add the following configuration to pom.xml

Now, when we run the following command, we will have a running tomcat server with our application deployed on it.

Next, Solving the step 3:

To start the selenium server from command prompt we need to do two things.
  • Add the dependency of selenium drivers to the app.  This is required so that we could use selenium api to programmatically write selenium testsThis is done using the following code:

  • Add the selenium plug-in so that we can start the selenium server from the command prompt.  This is done using the following code:

After this we can start the selenium server using the following command:

Next, Solving the step 4:

Now, we are ready to run the tests simply run the tests using the following command:

We have our selenium tests running as part of our maven build!  To do this we have to fire three commands from three command prompts/terminal windows.  One running tomcat, another running selenium server and the third running the tests.

All this is good but we don't want three command prompts running.  We just want one command that does it all!

And this is exactly what we are going to see next!

So as you already know that Maven is build around phases, we are going to run our functional tests (selenium tests) in the integration-test phase.

To run the selenium tests in the integration-test phase we have to do the following:
  1. Start the tomcat server
  2. Deploy the war
  3. Start the selenium server
  4. Fire the function tests
Here's how we do steps 1 and 2:

Above configuration means that following things in plain english:

  • Start the tomcat6 server
  • Deploy the app during the pre-integration-test phase.  
  • Stop the server during the post-integration-test phase.
You will have to define an environment variable CATALINA_HOME, which points to the tomcat server installation directory on your machine.

Next up, Step 3 do this:

Above configuration states the following:
  • Start the selenium server during the pre-integration-test.
  • Stop the server during the post-integration-test.
Next, Step 4: 

To run the functional tests during the integration-test phase, do the following (I promise this is the last bit of XML that you see on this post!)

This configuration does the following:
  • Tells maven-surefire-plugin to run the unit tests during the test phase but exclude the classes in the functional folder.
  • Run the test class in the functional folder during the integration-test phase.
And that's it my friend!  Now when you run the following command:

  1. Application will compile
  2. Unit tests will run
  3. War file will be created
  4. Tomcat server will be started 
  5. war file will be deployed on the tomcat started in step 4
  6. Selenium server will be started
  7. Functional tests will be fired
  8. And we will live happily ever after!

Sunday, October 17, 2010

How to append text and images to an existing PDF document


Recently in one of my projects we had a requirement that, we had to append some legal text and an image (in BMP, PNG or JPEG format) to an existing PDF invoice.

Now PDF is not a text format.  We can't simply add text and an image to the pdf document, by appending their bytes to the PDF file.  It requires special api's for manipulation. 

How do we do it:

iText framework has excellent support for manipulating PDF documents.  It can create, read, edit and append PDF documents.  Its really powerful!

But today we are specifically interested in adding some text and image to an existing PDF document.

Here's the code that can do this:

The generated PDF looks like this:

That's it!  The end result is we have a shining new PDF called "invoice-appended.pdf", which holds the content of the existing PDF and new information (text and image) appended to it.

How to convert HTML to PDF

Recently I was faced with a situation where, two days before the project was supposed to go into system testing phase, client had a change of mind (sounds familiar?  Sometimes I feel this happens quiet often).

In our project, we where showing an invoice as html, which the users could print.  Everything was fine, client was happy with the html invoice till the system testing was about to start.  Then one fine day, client decides they need the invoice as a PDF and not as an HTML.

Well, well, we had to deliver this in about a day.  The invoice was not really straight forward.  It changed based on different situations.

The project was build using Java technologies.

We had three choices:

  • Scrap all the effort (development and testing) that we had put in to get the HTML invoice in the format desired by the client.   Use some ugly api's to generate the PDF that would look similar to the HTML invoice we already had in place - Painful approach which would require a lot of effort.
  • Design a jasper report (jrxml) which would look exactly like the HTML invoice, then use jasper api's to render the designed report as PDF - Relatively sensible approach.  Jasper is extremely powerful (no doubts about that!), but people who have used Jasper in past would agree, designing a report in Jasper is not the easiest of the things.  It would take some time.  Moreover, the look and feel of the generated PDF might not be exactly like the HTML invoice.  In this approach also we might have to scrap all efforts we had put in generating the HTML invoice.
  • Find a way to convert HTML invoice directly into PDF - An awesome approach!  The effort we had put in to get the HTML invoice in the right format would not be wasted and everyone would live happily ever after!
I being a lazy developer, always choose the easiest approach.  Hence, I decided to give the approach #3 a shot.  Tried finding some frameworks that could convert HTML directly into PDF.

Some were good, some were bad and some were ugly.

But when I was trying these frameworks, I had a WOW moment!

Found a framework that would take the HTML and convert that into the exact same PDF!  It used the styles that were included in the HTML document and the generated PDF looked exactly like the HTML invoice!  I was thinking, Man this is Awesome!

The framework is called Flying Saucer

Internally Flying Saucer uses iText to genearte the pdf.  iText is really powerfull peace of software, it can genearte, read, edit, append pdf documents.

Lets look at the code to convert an HTML document directly into a PDF.

How do they do it:

That's it!  Pass the URL of the HTML invoice (we want to convert into PDF) to the create method.  Have a look at the generated PDF invoice file.

I was so amazed to look at the PDF file, it looked exactly like the HTML invoice.

To add to the joy, PDF is a paged medium.  Which means it could have page numbers, footers and headers.

Flying Saucer supports CSS 2.1 standards for paged medium and recognizes @page attribute in the CSS.  Hence, if you want page numbers at the bottom right cornor of your generated PDF, simply include the following styles in your HTML to be converted into PDF.

Simply, isn't it!
Note:  To convert HTML to PDF using Flying Saucer, your HTML should be a valid XML

Update: I have uploaded the sample code to convert html document in PDF here.

Saturday, October 16, 2010

How to run difference versions of IE (6, 7, 8) side by side on Windows 7/Vista

If you are a web-developer or a web-QA (QA who tests web-application), no matter where you work, what technology you use, what application you develop, there is always a need to test you application on various browsers.  Not just different browser from different vendors but different versions of the same browser. 

Although there are various ways in which we could get IE 6, 7, 8 running side by side on Windows 7/Vista.  All  of these techniques need installing some software or installing a VM image (which takes up approx 1 GB space on the hard drive).  In short its relatively long and painful process.

Some ways in which we could get various versions of IE running side by side are:

  • Installing IETester - Although its not a complete browser but shows the rendering of your application pretty well.  Works for IE 5.5, 6, 7, 8 and 9 (Great job IETester guys!).  Relatively pain free technique to test your application on various IE versions.  But its a difficult job to satisfy web-QA's, One of the QA's in my company said "I would not to believe IETester.  I want to test the application on actual IE 6"
  • Using the VM images - Relatively painful technique as it needs downloading VM images and Virtual PC software and a few more steps to get IE 6 and IE 7 running.
  • Another approach (again based on the VM image) is described here - In this approach IE6 window appears as a seamless window along with other applications running on your machine.  Nice approach, but still a lot of steps to get it running.
We need to test our app on various versions of IE but what about versions of Firefox, Chrome, Safari and Opera?

Web developers would agree that we need to test the application atleast on Firefox 2, 3, 3.5.

Sure there are ways to install them and get them running side by side, but none of them are as simple as clicking a button.

Although the title of this posts says getting different versions of IE running side by side on Windows 7/Vista, lets not ignore the other browsers and their versions.  Lets get them running on Windows side by side as well.

So how do we do it.  How do we get all these browsers easily?  It should be as simple as clicking a button.

How do they do it:

After all these years writing code, I have learned one thing and that is:

There always is a simpler way!  We simply need to find it.

Follow these steps to get different versions of IE, Firefox, Chrome, Safari and Opera running side by side on your machine, without installing too many software's on your machine.

  • It will ask you to install a plug-in so that you could run these browsers - Do that
  • After that if you hover over the image of any browser that you are interested in, you should see the green (power button) popping out - Click that
  • This will open up a dialog asking for user name and password - First time users can register for free - Do that
  • Next, A window will open up, this is an instance of your shining new desired browser - And you are good to go!

A note of caution: On slow internet connections this website could appear a little slow for the first run but subsequent runs are much faster.  Don't give up on it.  Its worth the wait!

That's it!  Have fun developing/testing your applications easily on various browsers and their different versions.
Have some Fun!