Saturday 29 March 2014

Performance increase in table lookup functions!!

Using object properties instead of QTP standard functions will improve the performance of QTP tests significantly. In our case, we often want to lookup the location of a certain value in a WebTable. QTP provides several functions to read out data from a table, but is slow when used iterating the table (like two for loops, one iterating the rows, the embedded second one iterating the columns per row).

Example of a conservative way to do this:

Public Function LocateTextInTable(byRef tbl, textToFind, byRef row, byRef col)

    For row = 1 to tbl.RowCount
        For col = 1 to tbl.ColCount
            If tbl.GetCellData(row, col) = textToFind then
                LocateTextInTable = True
                Exit function
            End if
        Next
    Next

    row = -1 : col = -1
    LocateTextInTable = False
End Function

The crux is this: .GetCellData is not a very fast method and with a table, consisting of 30 rows and 10 columns, this method is iterated up to 300 times in the most worse case scenario (= text not found).

A faster way to retrieve the data is through the Document Object Model (DOM). This allows you to use the more native properties of an object with the sacrifice of some ease of use.

A table consists of row elements and each row element contains one or more cells. We can iterate them just the same way as we did with the function above:

Public Function LocateTextInTableDOM(byRef tbl, textToFind, byRef row, byRef col)

    Dim objRow, objCell

    row = 1 : col = 1

    For each objRow in tbl.object.Rows
        For each objCol in objRow.Cells
            If objCol.Value = textToFind then
                LocateTextInTableDOM = True
                Exit function
            End if
            col = col + 1
        Next
        row = row + 1
    Next

    row = -1 : col = -1
    LocateTextInTableDOM = False
End Function

From our experience, this will increase the performance of the function with a factor 10.
But be aware, there is one big assumption: This function assumes that the row objects (and cell objects) are perfectly iterated from the first row to the last row and in this exact order. Although a For…Each construct cannot guarantee this behavior, we never encountered an incorrect location.

Sunday 23 March 2014

Automated Web Testing with Powershell !!!

I have beeen working in Selenium (see previous posts) building a test suite at my job. I spent quite a bit of time architecting the design and attempting to build bricks with which others could build buildings. I was beginning to instruct the folks on my team (who had not previously written code) on how to use these bricks and understand the mortar. This all in a language (Java) with which I wasn't terribly familiar. The framework design was sound and was beginning to grow on it's own.

Then, the massive changes in the app took place right about the time we were slammed with testing projects that required me to focus on manual testing. By the time the smoke cleared, the testing framework I had written was woefully out of date with the app. Many, many weeks were going to be required to update the component classes and test them all and I was not going to be given the time. Yet, automation was required and expected...right now.

So, what to do??

I have basically started writing tests in Powershell. Why PS? Writing the tests is relatively fast and it is incredibly powerful. I was able to create what I refer to as "QD" tests (Quick and Dirty) that support a happy medium between resusability and speed of development. I've tried to write them with maintainability mind, but not allowed that to override some basic ideas:
    1. Every test should be throwaway
    2. Anything that can't be thrownaway needs to be saved off for resuse
    3. Reusable pieces need to be elegant and very maintainable
    4. It is more important to generate a working test quickly than it is to write elegant code
    5. As quickly as possible, the tests need to be added to our periodic test suite
    

These ideas violate how I would prefer to write tests but in this volatile environment, I cannot invest much time in them. Instead, I write the reusable pieces well and as solid as I can. If the app changes two weeks from now, I am out very little as they can be replaced easily. 

The other benefit is that if I have only 2 hours last week to work on automation, I can probably produce something useful rather than try to ramp up from what I was doing last week. 

Again, this isn't how I'd like to produce tests but it's the best I can do in this situation.

I just hope the testing gods forgive the blasphemy.....


Sudhakar.Mangi

Thursday 13 March 2014

Curious QTP behaviour when using on error: Proceed to Next Step

Because we build our own framework, the on error settings in QTP are default on "Proceed to Next Step" for our unattended continuous script. So when a test is scheduled in the middle of the night, the test won't stall on errors like a function with an argument too few or many, an array that is out of bounds or an accidentally undeclared variable (please build an undeclared variable checker HP, the Patterson boys could do it years ago, you can do it too!).

It works fine most of the time, although debugging is done with an "attended run" script and all possible error detection on: Popup Message box and Option Explicit everywhere.

The curious behaviour happened in an Select Case. Consider this code:

Option Explicit
Dim myCondition : myCondition = 2
Select Case myCondition
    Case 1 MsgBox "Wooh! Condition 1"
    Case 2 MsgBox "Displaying undeclared variable: " & undeclared Variable
    Case 3 MsgBox "Meh, Condition 3"
End Select 

When you run this code in attended mode, you'll get a nice error nagging about the undeclared variable.
However, when you run this in unattended mode, you'll get a messagebox with the text: "Meh, condition 3"

QTP is doing what it says: Continue with the next step. But the step is not fulfilling the Select condition and program technical a major sin!
Because I ran this accidentally in unattended mode, it took me some while to get a finger behind the error. In the end, I learned to always debug in attended mode.

Tuesday 11 March 2014

Using Callbacks on the Regexp.Replace function !!

On our testprojects, I use regular expressions most of the time for the matching or testing of strings on our Application Under Test. But sometimes I have to use the Replace method of the RegExp object. This day, I discovered an advanced usage of the RegExp.Replace() method. Let me show you with an example:

Dim replacement
Dim regEx : Set regEx = New RegExp ' Create a regular expression.
Dim myString : myString = "Cake, and grief COUNSELING, will be Available at the CoNcLuSiOn of the test."

regEx.Pattern = "\b\w+\b" ' \b = inside word boundary, \w = word character,
                          ' so this pattern matches each single word
regEx.Global = True       ' Set the scope to Global

' normally we replace like this:
replacement = "word"
MsgBox regEx.Replace(mystring, replacement)

' resulting in: "word, word word word, word word word word word word word word word."

This looks familiar I think. But it is not very sophisticated. Wouldn't it be nice if we can replace each match with a custom replacement. With the use of a Function Reference, we can!

 ' We can actually perform a custom action on replace instead of doing a fixed replace
' We do this with making a reference to a function with getref
Set replacement = getRef("Capitelize")

' We need to create a function of course with the same name and three parameters
' 1. singleMatch : the string that matched to the pattern
' 2. position : the position the singlematch string was found
' 3. fullString : the full string (same as 'myString' in this case) without _any_ replacements
Function Capitelize(singleMatch, position, fullString)

    ' Capitelize returns the string singleMatch changed with the first character
    ' in uppercase and all others in lowercase
    Capitelize = ucase(left(singleMatch,1)) & lCase(mid(singleMatch,2))
End Function

MsgBox regEx.Replace(myString, replacement)
' This results in: "Cake, And Grief Counseling, Will Be Available At The Conclusion Of The Test."

Nice huh? Now we can match for a date and replace it on the fly by the correct format. We can replace straight quote characters for curly quotes with the correct orientation with much more ease, or only do a replace if it is within a certain character range in the string. "All new possibilities arise!"

--Sudhakar.Mangi

Sunday 2 March 2014

The Stack in Detail – Cucumber ,Capybara, Poltergeist and PhantomJS!!!!!!!!!!!!

Lets learn about Cucumber !!

what is cucumber?

Cucumber helps facilitate the discovery and use of a ubiquitous language
within the team, by giving the two sides of the linguistic divide a place where
they can meet. Cucumber tests interact directly with the developers’ code,
but they’re written in a medium and language that business stakeholders
can understand. By working together to write these tests specifying collaboratively
not only do the team members decide what behavior they need to
implement next, but they learn how to describe that behavior in a common
language that everyone understands.
When we write these tests before development starts, we can explore and
eradicate many misunderstandings long before they ooze their way into the
code base

Examples
What makes Cucumber stand out from the crowd of other testing tools is that
it has been designed specifically to ensure the acceptance tests can easily be
read—and written—by anyone on the team

Here’s an example of a Cucumber acceptance test:
Feature: Sign up
Sign up should be quick and friendly.
Scenario: Successful sign up
New users should get a confirmation email and be greeted
personally by the site once signed in.
Given I have chosen to sign up
When I sign up with valid details
Then I should receive a confirmation email
And I should see a personalized greeting message
Scenario: Duplicate email
Where someone tries to create an account for an email address
that already exists.
Given I have chosen to sign up
But I enter an email address that has already registered
Then I should be told that the email is already registered
And I should be offered the option to recover my password

How Cucumber Works?

Cucumber is a command-line tool. When you run it, it reads in your specifications
from plain-language text files called features, examines them for
scenarios to test, and runs the scenarios against your system. Each scenario
is a list of steps for Cucumber to work through. So that Cucumber can understand
these feature files, they must follow some basic syntax rules. The name for this set of rules is Gherkin.

Cucumber: Testing Web Applications With Capybara, Poltergeist and PhantomJS

Before we dive head first into the action we should take a moment to have a look at the tools that we will be using in addition to Cucumber (which has been Discussed above):
Capybara calls itself an “acceptance test framework for web applications”. Wait. Isn’t Cucumber already an acceptance test framework? Why do we need another? First, Cucumber is all about Behaviour Driven Development and not per se an acceptance test framework. You can work with Cucumber on the unit test level, or on the acceptance test level or anywhere in between. Second, Cucumber knows nothing about web applications. Cucumber only gives you the ability to write your tests (or specs or scenarios, whatever you call them) in a very readable, non-technical form (Gherkin) and to execute them. Capybara now integrates nicely with Cucumber in the Capybara docs) and hides the details of controlling a browser (via Selenium or Poltergeist) behind a nice API. It is just the right level of abstraction (for my taste) to make writing web application tests fun. Of course you could use something like Selenium directly in your Cucumber step definitions, but in my opinion that is too low-level and too verbose.
Poltergeist is labeled “a PhantomJS driver for Capybara” and that’s just what it is. It is the connection between Capybara and PhantomJS, see below. After registering Poltergeist as the driver in Capybara you do not interact directly with Poltergeist nor PhantomJS, only with the Capybara API.
PhantomJS is headless, full featured browser. It is based on WebKit and supports all important web standards (CSS, JavaScript, …). It is ideally suited for automated website tests because running it on a CI server (even without X installed) is a no-brainer.


---Sudhakar.Mangi