First, before anyone goes off, I'm referring to "Liberal" not in the political or social sense so common today, but in the classical sense, i.e. broad and varied, wide and all encompassing. One that covers lots of ground and develops a strong inductive core of knowledge and thought. History, Literature, Philosophy, Music, Art, Science, Mathematics, and OK, a smattering of business and perhaps some technology.
What's got me thinking about this right now? I owe it all to Dan. In this case, the Dan in question is Dan Carlin (he's guilty of so many of my "out there" thoughts, but hey, that's why I love him). In his most recent Common Sense podcast, called "Pie in the Sky Cynicism", he goes on a wide and wild ride through a lot of topics, but it was his point that he made about education that fascinated me. He made the case that, right now, there's a huge debate about the "value" of a college education. The expense of a degree is absurd, that is a fact, but it's often been sold as the fact that having a degree is a key to get us a good job and we'll be able to recoup our money. It's an investment in our future... but you better invest in something that's gonna' pay big!
Having considered this, Dan then said something I thought was quite profound and very interesting. His point was that, for those talking about the economic value of a degree, or going to a trade school to learn a trade and earn good money, are missing the point. Through history, the purpose and value of a liberal education was not to train someone for a trade or for a job. the purpose and value of a liberal education was so that we would be exposed to enough interesting things available in life and learn enough about the human condition that we would have a large, inductive body of experience to draw upon to do "anything". In short, the value of a liberal education is not the ability to make money, it's the ability to reason, to consider, and most importantly, to adapt.
I've whined about this in the past because, personally, I think History, Archaeology, Paleontology, Music, Philosophy, Epistemology, and Art are awesome. Sadly, today we're taught that studying this stuff will be limiting, that we will doom ourselves. Seriously, where's the money in history?
I find this sad and frustrating because we've lost something valuable in our quest to mint this current generation of bankers and technologists. There is, of course, a need for bankers and technologists, of doctors and policemen, of farmers and engineers, and all sorts of other jobs out there. Yet we have sacrificed some really interesting things in our educations because we've come to consider them not valuable.
I will say, though... there is a place where I firmly believe that the classic liberal arts education is immensely valuable, and yes, I believe that Software Testing is that place. Why? Because we are the ones who have to constantly reinvent our ideas and our ways of looking at the world. Testers are philosophers. Testers are historians. Testers are paleontologists. We are the "squints", to poach from Seely Booth. We ask the questions others won't ask. We look to what's gone on before to see what could happen going forward. Thus, we could and should be considered one of the last bastions of the true liberal arts education tradition, and maybe we need to start thinking of ourselves as such.
Note, in none of this have I said anything about "getting a degree", and that's on purpose. Part of this is my opinion that, sadly, I don't think a true, classic liberal arts education is available any longer. Judging from many of my friends who have graduated from Universities in the past two or three decades, they will certainly tell you that the classic liberal education, or even the desire to get it, is fading. Testers, it falls to us to protect the Agora, and frankly, I think the only way we will do it is if we embrace the ideas and ideals of a true, classic liberal arts education ourselves, and do so on our own accord and on our own terms. Not for money or profit, not for a sheepskin, but for its own sake. To reason. To think. Most importantly, to allow us to pivot and adapt to a world that refuses to stand still.
Michael Larsen, TESTHEAD
Thursday, January 31, 2013
Wednesday, January 30, 2013
PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Locators
This is the next installment (in progress) of my PRACTICUM series. This particular grouping is going through David Burns' "Selenium 2 Testing Tools Beginner's Guide".
Note: PRACTICUM is a continuing series in what I refer to as a "somewhat "Live Blog" format. Sections may vary in time to complete. Some may go fast. Some may take much more time to get through. Updates will be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom of the post, you will know that this entry is finished :).
Chapter 2: Locators
Much of the value of automation is that, ideally, we should be able to get tests that can run 100% reliably. Every time all the time automation is kind of a pipe dream, but we can still get high probability of success if we can give our tests reliable things to look at and do so in ways that are likely to succeed. If everyone practiced good web development protocols and everyone "followed the rules", then this would be easy.
Problem is, which rules? There's quite a few of them. Not considering the proliferation of "good practices", the fact is, a lot of teams,companies and projects don't practice good web development hygiene, or at least, not all of the time. It gets even hairier when the content is auto-generated. Not every element we want to interact with has a properly defined name attribute or id or css class name. In short, we need to have a broad and varied strategy to find what we are looking for. The nice thing is, Selenium allows for a broad and varied strategy to find what we are looking for :).
So what is an element? It's an item in a page that a person or a program can interact with. Links, buttons, images, text, controls, form fields, etc. are all elements. Each could be implemented with either the full compliment of accessibility options, or they could be the most absolutely bare bones of HTML. Either way, we want to be able to find the element we care about and interact with that element in a way that we can make a determination of a state is correct or not. We can use the following approaches to find what we are looking for:
- by ID
- by Name
- by Link
- by XPath
- by CSS
- by DOM
This section leverages Firebug, Firefinder, and the Developer Tools found with your favorite browser, so if you don't already have those, go to my first post in this series and look in the links section near the start and get what you need.
One quick way to see if you have the right name for the element you want to target is to open the IDE and type in the name of the element you want to interact with. If you enter that name, and then click the Find button to the right of the Target text box, you will either see a quick flash around the element in question on the browser page, or you will see an error in the log.
Finding ID's of Elements on the Page with Firebug
OK, yes, this may be old hat to a lot of people, but there are some out there who have probably never used Firebug or one of their analogs before (hint, if you have ever hit F12 for IE's developer tools, or you have clicked on Inspect Element in Google, you've used tools very similar to Firebug, and should be relatively easy to figure out).
- Navigate to http://book.theautomatedtester.co.uk/chapter2
- Click on the Firebug icon. It is in the upper left hand corner of your browser next to the Home and Favorites icon (at least, that's where it is for me).
Here's the bare basic and super fast version of using Firebug. If you point to an item on the screen, and then CTRL-click and select "Inspect Element with Firebug", you will see the element you clicked highlighted in the lower half of the window (the blue bar you see above). If It's formatted correctly, it will have some locator details you can use (name, link, ID, css class, something).
If you then use the up or down arrow and move the highlight, you can then look at other elements and see where they are on the screen and the locator details they provide. Sections such as head, body, divs and other "structures" in the html can be expanded/contracted. Mainly, for this chapter, we're using it to find names and other aspects we can use to put in the the "Target:" text box in the IDE. If you have that down, you're golden.
In the IDE example I just used verifyElementPresent and selected a couple of named items. Run the test and we can see that the test interacts with the items and confirms they are there. Not exciting, but it gets the point across.
Finding Elements by ID
An ID is a specific parameter given so that an element can be readily and uniquely identified. its syntax is easy to spot, as it shows up in a number of elements (images, links, fields, divs, etc.) as "id=someValue".
- Open Selenium IDE.
- Make http://book.theautomatedtester.co.uk the base url/
- On the first line of the script, put open in the Command: box and "/chapter2" in the "Target:" box.
- Click the Firebug icon on the browser.
- Look for the attribute id "but1". As you might guess, it's associated with a button.
- In the second line of the script, type "click" in the "Command:" box.
- In the Target box, type "id=but1". Click the "Find" button to see a flash on the browser page around the button to confirm the value is valid.
- Run the script.
By using an ID with elements, we help the script find an item that can be positioned, well, anywhere within a page. It doesn't need to be in a specific place; as long as the ID is present, and unique, we can use it to locate an element and interact with it. Note, in this case, the text will run without id=but1 being called out explicitly. Just putting in "but1" also works.
Finding Elements by Name
ID's are nice, but not everyone uses them. Sometimes, elements have a name attribute. Again, these are easy to find because the syntax they use is "name=someValue". Using Firebug, you can look at the elements on the page and see if a name is used instead of an id. You place that named item into the Target: text box, and can also use Find to confirm that the value is accessible.
- Open Selenium IDE.
- Make http://book.theautomatedtester.co.uk the base url/
- On the first line of the script, type "open" in the Command: box and "/chapter2" in the Target: box.
- Click the Firebug icon on the browser.
- Look for the attribute name "but2". Yep, it's associated with a button.
- In the second line of the script, type "click" in the "Command:" box.
- In the Target box, type "but2". Again, click "Find" to see a flash on the browser page around the button to confirm the value is valid.
- Run the script.
Also, if you want to be more specific, Target will let you put in "name=but1".
Just like in the previous example, id and name are being used in the same way. The script will recognize the element by either means of identification. Having an id or name means the element can be anywhere on the page and as long as the name or id is unique, the script will find it.
Sometimes there can be several named items that share the same name. When this happens, a "value=someValue" tag can be used. This helps to make sure that you identify the right element. in the IDE, type "name=someName" followed by "value=someValue" to locate the specific element you are after:
Note, in the book, the example is displayed as follows:
name=verifybutton value=chocolate
However, when I do that, I get an error message.
First, the value is no longer valuebutton, but valuebutton1.
Second I'm not sure if this is type-setting, a difference w/ Ubuntu and Darwin, or 1.5.0 and 1.10.0 versions of IDE, but if you want to use the value attribute, you need to put it in the Value: column. To do that, in the Value textbox, type:
value=chocolate
And then run the script. This time it will work.
Finding Elements by Link Text
We are most familiar with links on pages, since they are what we actually click to get from one page to another. Likewise, Selenium lets you target links and interact with them. By using "link=linkName" we can access and use the link attributes to do any number of operations.
http://book.theautomatedtester.co.uk/chapter2 has a link that points to the Index page for the site. In the IDE:
- type "click" into the command text box.
- type "link=Index" in the target box
- Run the script.
Net result, the user is taken to the index page, as intended.
Finding elements by accessing the DOM via JavaScript
Sometimes pages get updated dynamically. AJAX and other "what's new this instant" methods make for an interesting challenge. In short, we don't necessarily know what is going to be there when we load or reload a browser. AJAX physically updates the Document Object Model (DOM), so we need to have some technique to tell us if the document element we care about is actually there, and is intended to be there.
Using JavaScript, we can do this.
An example JavaScript call to look for the first link on a page would be document.links[0]; document in this case means our HTML file. links is an array within the object "document". The zero represents the first of the links to be found in that document.
- Open Selenium IDE
- Set the base URL to http://book.theautomatedtester.co.uk/
- On the first line of the script, use the command "open" and the target "/chapter2"
- On the second line of the script, use the command "click" and the target "dom=document.links[0]"
- Save and run the script.
Our net result is that we can reference that first link on the chapter 2 page and interact with it. In short, the example above and the previous example with the link text do the exact same thing.
Finding elements by XPath
Sometimes, the markup is even more dynamic than the example above. the element in question might be even harder to find because aspects of its id or name changes, or its based on something that's not inherently obvious. For these times and situations, XPath is an option. XPath allows for complex queries, and gives us a way to get to elements we might not otherwise be able to access.
Here's the example that David gives for the Chapter 2 page:
Let's start by creating a basic XPath. We are going to look for an input button:
- Open Selenium IDE
- Set the base URL to http://book.theautomatedtester.co.uk/
- On the first line of the script, use the command "open" and the target "/chapter2"
- On the second line of the script, use the command "click" and the target "xpath=//input"
- Click the "Find" button to see the element selected.
- Highlight the click line and press 'x'. The command executes and it clicks the button.
The ''//" means find the first element that matches this. Dave points out that this is a greedy query; if you have large passes to traverse, it could take awhile before it returns your value. An alternative is to use a single slash and make a more explicit call, such as in the following example:
- Open Selenium IDE.
- Make http://book.theautomatedtester.co.uk the base url/
- On the first line of the script, put open in the Command: box and "/chapter2" in the "Target:" box.
- On the second line, type click in the command box, and put "xpath=/html/body/div[2]/div[3]/input" in the target box.
- Click "Find" next to the target box.
This example gives a much more focused query, and it also defines an exact region in the HTML to check. Down side, if the HTML changes, the test will break. Greedy search but flexible, or focused search and brittle. Hey, them's the tradeoffs!
What happens when you get a button or a range of them that don't have a unique name or ID. If the items are all similar enough, you can address them as an array.
In chapter 2, there are three div elements. Which one do you mean? "//input" will give you the first item. "//input[2]" will give you the second element, provided it's of the same level as the first element returned. If they aren't at the same level, you'll get a failure; the system will say it can't be found.
Try this:
We can see this with the input buttons that are present on the page. They all reside in their own containing div element, so do not have any sibling elements that are also input elements. If you were to put //input[2] into Selenium IDE, it would not be able to find the element and fail.
Well, that's what's supposed to happen, but ya' know what? I just tried this out, and I'm able to make it work as listed. It's supposed to error out, but as is, I can access both of them with this array approach.
See?
Using element attributes in XPath queries
If elements are the same but have some slight differences in attributes, you can use that to your advantage. By using "xpath=//element[@attribute='attribute value']", you can make distinctions between elements.
Try this:
- Open Selenium IDE
- Navigate to http://book.theautomatedtester.co.uk
- Open /chapter2
- Enter the following statements into their own lines using the Target:
//input[2]
//div[@class='mainheading']
//div[@class='mainbody']
//div[@class='leftdiv']
//div[@id='divontheleft2']
Clicking on the 'Find' button will show where all of these areas are and that they are accessible.
XPath for Partial Match of Attribute Content
Sometimes you just can't create a completely determinable element. Dynamically generated content may use something like a time stamp.
Sometimes only part of the ID is changing. Some of it might always be the same, so you could use that part as a reference point. XPath let's you do a partial match.
Think of it this way… let's say that an element has a dynamic timestamp, but it starts with the word time.
Open Selenium IDE
Enter the following items on their own lines:
//div[contains(@id,'time_')]
//div[starts-with(@id,'time_')]
Click 'Find' and you will see that they reference the same thing.
XPath to Help Find an Element via Text
Sometimes the text in an element can be a helpful place to look for an identifier when there isn't anything else to use.
By using the text attribute "//element[text()='inner text']", you can find stuff on the screen, like this:
Start Selenium IDE
Enter the following XPath line:
//div[text()="This element has a ID that changes every time the page is loaded"]
//div[contains(text(),'element has a ID')]
See, same thing, different use:
Looking for Elements using the XPath Axis
As if XPath didn't already have a decent arsenal of tools to try to access elements (I feel like the RonCo guy when he says "now how much would you pay" and "but wait, there's more!"), there's another trick that XPath provides. Not content to just give you search options and arrays, you can even look for stuff that's near something else.
xpath=//div[@class='leftdiv']/ input[2].
Let's start with an element we can find directly:
//input[@ value='Button with ID']
Place this into the target text box and click 'Find'. You'll see the button it highlights. There's another button right below it. This button is the next in line as far as the DOM is concerned. It's a "sibling" element. To access it, we could do so directly… but what fun is that ;)?
XPath has an option called "following-sibling", and it's used like this:
//input[@value='Button with ID']/following-sibling::input[@ value='Sibling Button']
This following-sibling syntax is showing us how we can reference elements not just by their direct identification, but also their relative position to other elements. That can be very powerful, in that we may need to check a group of elements to make sure that the group is being represented correctly and in the proper order.
We could also go the opposite direction, stating with the 2nd element and pick the one just prior to it. To do that, we reverse the order and use the preceding-sibling option, like this:
//input[@ value='Sibling Button']/preceding-sibling::input[@value='Button with ID']
See? Both are able to reference each other in both directions:
To see how to access a variety of axis elements, here's a list of XPath queries you can use:
ancestor Selects all the ancestors (parent, grandparent, and so on) of the element
descendant Selects all the descendants (children, grandchildren, and so on) of the element
following Selects all elements that follow the closing tab of the current element
following-sibling Selects all the siblings after the current element
parent Selects the parent of the current element
preceding Selects all elements that are before the current element
preceding-sibling Selects all of the siblings before the current element
Finding Elements by CSS
XPath has some cool aspects to it. They can also be greedy and time consuming. Another approach is to use CSS selectors if they are in place. Selenium is compatible with CSS 1.0, CSS 2.0, and CSS 3.0.
The syntax for using CSS is:
css=cssSelector
Let's try it out…
- Open Selenium IDE.
- Navigate to http://book.theautomatedtester.co.uk/chapter2
- Click on the Firebug icon.
- Click on the Firefinder tab in Firebug.
- Look at one of the buttons in the div with the ID divontheleft.
- The CSS Selector for the buttons would be "div.leftdiv input".
- Place that into FireFinder and click on the Filter button.
You'll see the following:
- Put css=div.leftdiv into the Target textbox, click the Find button.
If we put in css=div.leftdiv input into the Target pox and click find, only the first button will light up.
Using Child Nodes to Find the Element
"div.leftdiv input" will look look for the div, then it will look for an input node in the DOM below leftdiv. This works similar to "descendant" in an XPath query.
By putting ">" between the div selector and the input selector, like this:
css=div.leftdiv > input
We can find the child of the element.
Using Sibling Nodes to Find the Element (CSS)
Using XPath, we can use "following-sibling" in the XPath Query. To do the same in CSS, we use a "+" between items in the query. This checks the direct next node to see if its a match.
In the following example there are two buttons. So far, our examples have found the first button. This time let's find the second button:
"css=input#but1" will find the first button.
but1 sibling is the "br" tag. The "br" tag's sibling is "input".
To make this selector, we would enter the following:
css=input#but1 + br + input
Unfortunately, putting it in as described gives me the following
Now, if we put in just #but1, it lights up. If we put in "+ br" and click find, the br lights up. It's just when we put in the next command, the + input, that we get the error.
Using CSS Class Attributes in CSS Selectors
Finding elements by their CSS class starts by calling the CSS class first, and then moving through the DOM via descendent nodes to find the element.
The syntax looks like this:
css = node.class
To find the div with the class centerdiv, type:
css=div.centerdiv
Using Element IDs in CSS Selectors
CSS also allows for using IDs to help locate elements. To look for elements by ID in a CSS selector, put a "#" in front of the ID of the element.
To find the ID of divinthecenter, the CSS selector would look like this:
css=div#divinthecenter
Or simplify to:
css=#divinthecenter
See, both due the same thing:
This works this way because ID's have to be unique.
Finding Elements by Their Attributes
Like XPath, CSS lets you look for attributes of elements, too.
There's a button that has the value chocolate. For web page buttons, value == what you actually see on the screen.
The syntax for attributes is:
node[attribute='value']
So for the button with the value "chocolate", we want to use:
css=input[value='chocolate']
Which looks like this when you use it:
David shows an example using href. On the Index page, you could put in the following:
css=a[href='/chapter2']
If you click the Find button, it will highlight the Chapter 2 link. Follow it, and it will take you to the chapter 2 page.
Want to make sure you're hitting the right element? Use chaining. Put two attributes together, like this:
css=node[attr1='value1'] [attr2='value2']
Use the following with but1:
css=input[id='but1'][value='Button with ID']
Just in case you happened to have two but1 buttons, this extra step makes it clear which one you mean.
Partial Matches on Attributes
XPath lets you use "contains" to make partial matches for values. We can do something similar in CSS to make partial matches, too:

^= Finds the item starting with the value passed in. This is the equivalent to the XPath starts-with.
$= Finds the item ending with the value passed in. This is the equivalent to the XPath ends-with.
*= Finds the item which matches the attribute that has the value that partially matches. This is equivalent to the XPath contains.
Comparison:
XPath : //div[contains(@ id,'time_')]
CSS : div[id^='time_'] or div[id*='time_']
To put these in the IDE, do the following:
xpath=//div[contains(@ id,'time_')]
css=div[id^='time_']
css=div[id*='time_']
Finding The nth Element With CSS
To find the second input after the div with the class leftdiv, XPath let us use
xpath=//div[@class='leftdiv']/input[2]
CSS doesn't exactly have a similar analog. To find "second to nth" elements, there is an approach called "pseudo-classes".
A Pseudo class lets a user add a "special effect" to a selector.
This example assigns ":nth-child" for the first example.
Open Selenium IDE.
Navigate to http://book.theautomatedtester.co.uk/chapter2
Type css=div#divinthecenter *:nth-child(3)
Click Find. You'll see the button that says chocolate gets highlighted.
Note: :nth-of-type can't access the specific type. The selector uses the wildcard "*" and then looks for the nth- child from the starting div.
OK, wow, that was a lot of stuff to get through. For the record we are now 35% of the way through the total volume of the book, and have completed just two chapters to do it! It's one thing to do a "yeah yeah, I get it" while reading through these, it's quite another to actually walk through all of them, try them out, make sure they work the way that we expect them to, and put them into practice one at a time.
I really appreciate the time the David took to put all of these examples together. Some of them turned out to be a little different than printed, but such is life. For the most part, the examples work as they are portrayed. The lesson I'm taking out of this is that, when using a locator scheme, be explicit. Call out exactly what locator approach you want to use, and fill in the details for each.
End of Section
Michael Larsen, TESTHEAD
The Value of "That One Person"
Over the years, I have often wondered what set my direction, what got me to make what I like to call "hinge pin" decisions in my life. Some of the things in my life have been relatively constant. I like to believe that things like my faith, my integrity, my morality and my convictions have been relatively stable, though they have certainly fluctuated over the years. Hinge pin decisions are those things that take people in very different directions, or making significant decisions that change the course of their existence.
I think, very often, hinge pin decisions are almost always caused by people. More to the point, they are caused by one or two people, where a deep and profound connection is made. A best friend growing up can have a profound effect on the way that you view yourself, and the things that you value and want to aspire to. A romantic relationship can often be the deciding factor as to where you will live or what you choose to do with your time. A work relationship can be the deciding factor to going into a particular career.
In short, whenever things change, or we get excited about something, or we become obsessed with some aspect, most of the time, you can point to a person or people helping influence that decision. When people ask me why I became a software tester, I could point to lots of different aspects (personality, work ethic, interests, etc.) but the truth is, I went into software testing because software testers befriended me when I was young. If I had been brought into a software development group, and I'd had a similar relationship with the coders, or perhaps the rework team, or heck, the accounting department, it's possible some key person there may have influenced me to go do something else with my life. My friend Gordon was the key to getting me to join the revolution that was Snowboarding in the early 1990s. A friend from school and his passion excited me enough to want to become a musician. My best friend growing up did many things that caused the two of us to have a little game of "one up" with each other over the years. I joke that this relationship often caused us to take on all sorts of things and endeavors in our youth that neither of us would have done had we not known each other. My experiences with repertory theater, soccer, baseball, skiing and even doing a stint as a model in my teens ties directly to him.
So what's my point with this? It's people that make or break the big things. Many of my best interactions over the years in a variety of endeavors were what they were because of a close connection with a person. Many of the fall-outs I have had have not so much been due a disintegrating relationship, but often because of the removal of that person from the picture. I can point to a number of times when the highs were due to a particular person(s) presence and interaction, and when the downward slide was precipitated because of a particular person(s) no longer being there. We like to believe the work is what engages us, and for many, it might be, but never dismiss the people from the equation, especially the value of 'That One Person" at that given point in time. Without them, your (and my) life might be very different today.
Michael Larsen, TESTHEAD
I think, very often, hinge pin decisions are almost always caused by people. More to the point, they are caused by one or two people, where a deep and profound connection is made. A best friend growing up can have a profound effect on the way that you view yourself, and the things that you value and want to aspire to. A romantic relationship can often be the deciding factor as to where you will live or what you choose to do with your time. A work relationship can be the deciding factor to going into a particular career.
In short, whenever things change, or we get excited about something, or we become obsessed with some aspect, most of the time, you can point to a person or people helping influence that decision. When people ask me why I became a software tester, I could point to lots of different aspects (personality, work ethic, interests, etc.) but the truth is, I went into software testing because software testers befriended me when I was young. If I had been brought into a software development group, and I'd had a similar relationship with the coders, or perhaps the rework team, or heck, the accounting department, it's possible some key person there may have influenced me to go do something else with my life. My friend Gordon was the key to getting me to join the revolution that was Snowboarding in the early 1990s. A friend from school and his passion excited me enough to want to become a musician. My best friend growing up did many things that caused the two of us to have a little game of "one up" with each other over the years. I joke that this relationship often caused us to take on all sorts of things and endeavors in our youth that neither of us would have done had we not known each other. My experiences with repertory theater, soccer, baseball, skiing and even doing a stint as a model in my teens ties directly to him.
So what's my point with this? It's people that make or break the big things. Many of my best interactions over the years in a variety of endeavors were what they were because of a close connection with a person. Many of the fall-outs I have had have not so much been due a disintegrating relationship, but often because of the removal of that person from the picture. I can point to a number of times when the highs were due to a particular person(s) presence and interaction, and when the downward slide was precipitated because of a particular person(s) no longer being there. We like to believe the work is what engages us, and for many, it might be, but never dismiss the people from the equation, especially the value of 'That One Person" at that given point in time. Without them, your (and my) life might be very different today.
Michael Larsen, TESTHEAD
Tuesday, January 29, 2013
Proof of A Little Each Day
A year ago, I mentioned that I was inspired by the Jerry Seinfeld approach of "Chains", meaning making a chain of events, and doing everything you can to keep that chain of events going as long as you can.
This same idea is also well represented in Aesop's fable "The Crow and the Pitcher". In it, a crow, dying of thirst, comes to a large stone pitcher of water with a narrow neck. The pitcher is heavy, immovable to the crow, but more important, the pitcher has some water in it, enough to save the bird's life. The issue? There's no way for the bird to reach the water... until she starts picking up numerous pebbles and dropping them, one by one, into the jar. Over a considerable amount of time, but with patient effort, at last the water reached the neck of the pitcher, and the crow is able to drink and save her life.
That may be a bit over dramatic, but it illustrates a point. Sometimes, we can make tremendous feats of energy, strength and bravery to reach a goal, but most of the time, skills are developed slowly, a pebble at a time. Being patient through that process can be hard, but a little each day can work wonders on, well, anything.
This past month, I've done everything I can to have at least one blog post a day, and to have more than one on standby in case I can't post on a given day. This has had two effects. First, it's meant that I don't write as much (meaning sheer volume in a given post), but the little bit I do write equals up to more than trying to make those herculean lifts.
I found something interesting in this approach. It should come as no surprise that, the more that you write, the more that you find you can write, and with greater ease, because it becomes a daily habit.
Additionally, one of the things I've found working against me for a number of the initiatives I wanted to do was that I always considered each item a blog post, as though the post were an atomic unit. Don't publish until everything is done. For the vast majority of stuff, that's exactly what I do. There's one exception, and that's when I go to events. There, I "Live Blog". I warn everyone that the content will be chaotic, the terminology may be messy, the grammar may suck, but I go back and do clean-up later, and let people enjoy the "experience" as it happens. For the most part, people are cool with that, appreciate the idea that it's an ongoing thing, and that I'll add to it as the event goes on. The net result is that those posts tend to be the length of book chapters (or more) at times, but I never write them in one sitting. Instead, I write them over the course of several hours, and publish them piece by piece.
I realized that I could do the same thing with my PRACTICUM posts. I've always hashed on them until I had a fully finished section. Sometimes that would be simple and take a day, sometime it might take a week or more. When it took a long time, I'd often get discouraged and go do something else. It also tended to stop up the pipes of any other "creative ideas", because "I have to get that next chapter reviewed for "fill in the blank" before I can do anything else".
Today, I am taking a different tack to this. I'm working on a series right now that will probably go for several days, maybe even several weeks, but I want to make sure that I keep writing and publishing something every day (it's a promise I've made to myself). Thus, from here on out, my PRACTICUM posts are going to be "semi-Live Blog" entries. What that means is each post will be a work in progress, and labeled as such, until I finish a given section. At that point, I'll mark it complete, inform all who may care, and move on to the next one. This way, I can actually write more, learn more, and keep my pledge to "do a little each day". Likewise, anyone who wants to can see the posts develop in real time (of sorts), and possibly help me make sense of things I might be struggling with as well, without the feeling that the post has reached "finality".
This may succeed swimmingly, it may fail miserably, but hey, nothing ventured, nothing gained. Here's hoping y'all will come and join me on this mad adventure :).
Michael Larsen, TESTHEAD
PRACTICUM: Selenium 2 Testing Tools Beginner's Guide: Getting Started with Selenium IDE
Note: this is a somewhat "Live Blog" entry, meaning I'm going to update as I go through and have comments. These may be daily, they may be more frequent. Feel free to click refresh to get the latest version at any given time. If you see "End of Section" at the bottom, you know that that one is finished :).
Way back in the Fall and Winter of 2010, I introduced an idea on my blog called PRACTICUM. The idea was that I wanted to see if the exercises in a book lined up with a real world user, and what would I think of the outcome and examples? More to the point, would a book that looked reasonable on the surface actually work in real life for a user, perhaps one with not the exact same setup?
These were the ideas that went into the Practicum series I did, and the first book I tried to tackle was David Burns' "Selenium 1.0 Testing Tools Beginner's Guide". Things went swimmingly for several chapters, and then things started to go very wrong, to the point where I couldn't continue. For the record, it wasn't David's fault; the Windows implementation of Selenium RC w/ Java was flaky at the time, and I just plain got stuck. I've felt bad that I haven't gone back to rectify this for two years now, so I decided to do something about it, and that something starts today.
In the spirit of "a little code every day", I've decided to revisit this topic, effectively "mothball" the first books posts, and do the whole thing over again with David's Second Edition book, "Selenium 2 Testing Tools Beginner's Guide". Why? Lots of reasons.
First, it will give me a chance to see if running on a Mac w/ Darwin will work better than running on a PC with Windows 7.
Second, a lot has changed in the world of Selenium since 2010, and I want to see how much and in what ways.
Third, I've been meaning to do a proper review of Selenium 2 Testing Tools for months now, and having reviewed Unmesh Gundecha's Selenium Testing Tools Cookbook made me decide this was as good a time as any.
Finally, the PRACTICUM posts force me to be honest. I can't just skim a book and say "hey, this was good" or "well, it didn't quite jive with me". Nope, I have to bite the bullet, work through each example, in somewhat real time, and talk about what's good, what sucks, where I'm brilliant, and where I'm stupid. Probably multiple times of each in the same post :).
Thus, without further ado, PRACTICUM commences once again. Thank you, David Burns, for being the inspiration.
"Selenium 2 Testing Tools Beginner's Guide"
For those who have the first volume, I will say that David has faithfully stuck to the same format as the First Edition, and this helps a lot for those who have read the previous volume; it grounds everything in the same context, and it makes me go "oh yeah, I remember that!". The examples also roll a lot faster this time, too, for the same reason. thank heaven for familiarity :).
The Preface is a good place to start, as it tells us what we are going to need to be successful. Again, I'm slightly off the mark because I'm not using Ubuntu, I'm using Darwin, but it's closer to the mark than I was the first time with Windows 7. For those wondering what you will need, and where to get them, start here:
Installing everything is quite simple. Run the steps that each tool tells you to, restart your system or browser if necessary, get this done first thing so you're ready to go when you need to.
Chapter 1: Getting Started with Selenium IDE
OK, yes, I know some of you are already rolling your eyes… that whole "friends don't let friends record and play back" bit, I know... well ,*can* it! At least for a little bit. I said I'd review the book serially and that's exactly what I'm going to do. David chooses to start out the book with the IDE in the first few chapters, so IDE it is.
The first step, Install the IDE
[Simple enough, really, just go to http://seleniumhq.org/download/ and pull down the most recent version (which as of this writing is 1.10.0). Likewise, you could just open up Firefox, go to add-ons and do a search for Selenium IDE. Select it, install it, restart the browser, and there you are.]
Next step, Record our First Test
[ Hit record and go to http://book.theautomatedtester.co.uk/chapter1
Click on the radio button.
Select "Selenium RC" from ther drop down box.
Click on the "Home Page"link.
Stop recording.
Click Play on the IDE.
What you get looks like this:
Updating a test to assert items are on the page
In the previous examples we were able to interact with certain elements. This may be enough for some tests, but what if we want to make sure something is there that we are not specifically calling out in the test steps, like a key word or value?
Again pretty basic, but getting a little more interesting.]
Adding Selenium IDE comments
If you want to insert a comment, it's easy to do so:
[
Multiplying Windows
What do we do when windows proliferate (pop up windows, different screens, etc.)? We keep track of them by using child processes. Selenium IDE helps us do that in the following manner:
Working with AJAX
The next example shows us an initial AJAX test.
What does running this test tell us?
A number of these commands are run implicitly when other commands are being run. An example of this is the clickAndWait command. This will fire off a click command and then fire off a waitForPageToLoad. Another example is the open command which only completes when the page has fully loaded.
This next example takes a look at what we need to do to use another AJAX control and wait for the element to appear. Same steps as before:
Fire up Selenium IDE and set it to record.
Click on the load text to the page button.
Navigate to http://book.theautomatedtester.co.uk/chapter1.
Click on the "load text to the page" button.
Wait for the text "I have been added with a timeout"
Note, steps 1 and two are backwards in the book. Not a big deal, pretty easy to figure out what to do in this case. What's not so clear is that the output does not look the same. This is what happens on the page when we follow the directions:
Debugging Tests
There are a few neat little things that you can do to walk through and see how thing will work in your tests. The first is that, if you highlight a row in the IDE, and press the 'x' key on your keyboard, you can execute that single step. You can also click the pause button after pressing play, and that will halt the test at that point, clicking the pause/replay button acts as a toggle, so that you can step through each case (adjust the playback option to get better control of this). Also, clicking on the Find button next to the Target text box will momentarily flash a yellow highlight on the page, showing you where that target is. If the IDE cannot find a target, it will print an error in the log. You can also use echo as a Command and put ${variableName} as the Target to see what the value of the variable is, like this:
Breakpoints can also be enabled at a certain line in the script. to do that, ctrl-click and select "Toggle Breakpoint". This will create a stopping point for your test.
What You Can't Record (at least not yet)
At this point, there are some things that record and playback just doesn't work with, as well as interactions that are just not supported with Selenium IDE. David gives us a brief list here:
Some of these examples will have ways to deal with them later when we get into WebDriver.
Summary
22% of the books total volume just got covered in this initial chapter! Granted, a lot of that was due to pictures of the IDE and what to see in the screenshots. Still, this is a pretty impressive overview; for the most part, everything as explained works right out of the box. There are some differences in the presentation format and some values, and how the tool responds to them, but again, I think a fair amount of that falls into version differences between what was available when the book was written and what's available now. Also, there's a couple of places where there are small omissions, and these I think fall into the category of "implicit knowledge" (highlighting text to actually be able to access the commands associated with that element. Easy to see once you've done it once or twice.
So far, so good!
End of Section
Michael Larsen, TESTHEAD
Way back in the Fall and Winter of 2010, I introduced an idea on my blog called PRACTICUM. The idea was that I wanted to see if the exercises in a book lined up with a real world user, and what would I think of the outcome and examples? More to the point, would a book that looked reasonable on the surface actually work in real life for a user, perhaps one with not the exact same setup?
These were the ideas that went into the Practicum series I did, and the first book I tried to tackle was David Burns' "Selenium 1.0 Testing Tools Beginner's Guide". Things went swimmingly for several chapters, and then things started to go very wrong, to the point where I couldn't continue. For the record, it wasn't David's fault; the Windows implementation of Selenium RC w/ Java was flaky at the time, and I just plain got stuck. I've felt bad that I haven't gone back to rectify this for two years now, so I decided to do something about it, and that something starts today.
In the spirit of "a little code every day", I've decided to revisit this topic, effectively "mothball" the first books posts, and do the whole thing over again with David's Second Edition book, "Selenium 2 Testing Tools Beginner's Guide". Why? Lots of reasons.
First, it will give me a chance to see if running on a Mac w/ Darwin will work better than running on a PC with Windows 7.
Second, a lot has changed in the world of Selenium since 2010, and I want to see how much and in what ways.
Third, I've been meaning to do a proper review of Selenium 2 Testing Tools for months now, and having reviewed Unmesh Gundecha's Selenium Testing Tools Cookbook made me decide this was as good a time as any.
Finally, the PRACTICUM posts force me to be honest. I can't just skim a book and say "hey, this was good" or "well, it didn't quite jive with me". Nope, I have to bite the bullet, work through each example, in somewhat real time, and talk about what's good, what sucks, where I'm brilliant, and where I'm stupid. Probably multiple times of each in the same post :).
Thus, without further ado, PRACTICUM commences once again. Thank you, David Burns, for being the inspiration.
"Selenium 2 Testing Tools Beginner's Guide"
For those who have the first volume, I will say that David has faithfully stuck to the same format as the First Edition, and this helps a lot for those who have read the previous volume; it grounds everything in the same context, and it makes me go "oh yeah, I remember that!". The examples also roll a lot faster this time, too, for the same reason. thank heaven for familiarity :).
The Preface is a good place to start, as it tells us what we are going to need to be successful. Again, I'm slightly off the mark because I'm not using Ubuntu, I'm using Darwin, but it's closer to the mark than I was the first time with Windows 7. For those wondering what you will need, and where to get them, start here:
- Mozilla Firefox (http://getfirefox.com)
- Google Chrome (https://www.google.com/chrome/)
- Internet Explorer (http://windows.microsoft.com/en-US/internet-explorer/downloads/ie-9/worldwide-languages)
- Opera (http://www.opera.com/)
- Intellij IDEA (http://www.jetbrains.com/idea/)
- Selenium IDE (http://seleniumhq.org/download/)
- Selenium Grid (http://selenium-grid.seleniumhq.org/)
- Ubuntu Linux (http://www.ubuntu.com/, but again, I'm rocking' this one on Darwin. We'll see if I regret it in a bit :) ).
Installing everything is quite simple. Run the steps that each tool tells you to, restart your system or browser if necessary, get this done first thing so you're ready to go when you need to.
Chapter 1: Getting Started with Selenium IDE
OK, yes, I know some of you are already rolling your eyes… that whole "friends don't let friends record and play back" bit, I know... well ,*can* it! At least for a little bit. I said I'd review the book serially and that's exactly what I'm going to do. David chooses to start out the book with the IDE in the first few chapters, so IDE it is.
The first step, Install the IDE
[Simple enough, really, just go to http://seleniumhq.org/download/ and pull down the most recent version (which as of this writing is 1.10.0). Likewise, you could just open up Firefox, go to add-ons and do a search for Selenium IDE. Select it, install it, restart the browser, and there you are.]
Next step, Record our First Test
[ Hit record and go to http://book.theautomatedtester.co.uk/chapter1
Click on the radio button.
Select "Selenium RC" from ther drop down box.
Click on the "Home Page"link.
Stop recording.
Click Play on the IDE.
What you get looks like this:
Again, not setting the world on fire, but simple first steps help get people to be confident and try bigger things. The point to this is that something is happening, and we can actually see it doing its thing.]
Updating a test to assert items are on the page
In the previous examples we were able to interact with certain elements. This may be enough for some tests, but what if we want to make sure something is there that we are not specifically calling out in the test steps, like a key word or value?
We can do that with assert or verify. An assert will test to see if a value exist. If not the test ails and stops. If verify fails, a failure is marked but the test will continue.
Selenium IDE adds a context menu to Firefox. right-click (or Control click on Darwin) to see it.
[ Example:
Selenium IDE adds a context menu to Firefox. right-click (or Control click on Darwin) to see it.
[ Example:
- Start recording.
- Navigate to http://book.theautomatedtester.co.uk/chapter1.
- Select "Selenium Grid" from drop-down.
- Verify "Assert that this text is on the page" is present by selecting "Verify TextPresent Assert that this text is on the page" (ctrl-click on Darwin).
- Hover over the button that says "Verify this button he here" is on the page (seriously, it says that ;) ). (ctrl-click and select "verifyElementPresent with the target verifybutton".
- Stop recording.
- Click playback.
Again pretty basic, but getting a little more interesting.]
Adding Selenium IDE comments
[
- In the current test, ctrl-click the verify step.
- Click on Insert New Comment.
- Click on the Command textbox and enter in a comment.
- Run the test.
And there you have it. ]
What do we do when windows proliferate (pop up windows, different screens, etc.)? We keep track of them by using child processes. Selenium IDE helps us do that in the following manner:
- Open up Selenium IDE and go to the Chapter 1 page on the site.
- Click on the second line that has the text "Click this link to launch another window".
- When the window appears, ctrl-click over the top text and select "VerifyText id=popup text".
- Click the "Close the Window" text. It will ,well, close the window.
- Stop Recording.
- Press Play.
It looks like this:
This is deceptively simple, but it's very cool. What we are seeing is the fact that, by tagging the individual pop up windows and giving them unique ID's, we can manage the flow of the test, direct our processes to the correct windows, and do so in the right order.
Here's how to do it with two pop-up windows:
- Click record. Go to the Chapter 1 page on the site.
- Click on "Click this link to launch another window" link (the first one). This will launch a pop up window.
- (ctrl-click), and select "assertText".
- Go back to the parent window, click on the second "Click this link to launch another window" link. This launches a second pop-up window.
- Verify the text on the page.
- Move to the first pop-up window. Click "Close the Window" and close it using the close link. Notice the "clickAndWait" command.
- Move to the second pop-up window. Click "Close the Window".
- Go back to the parent window and verify an element on that page.
Working with AJAX
The next example shows us an initial AJAX test.
- Start up Selenium IDE, start recording.
- Go to http://book.theautomatedtester.co.uk/chapter1.
- Click on the text that says "Click this link to load a page with AJAX".
- Verify the text that appears on your screen.
Hmmm, that doesn't look right. Good news, though, at this stage, it's not supposed to. We need to include a command before the verify text called "waitForElementPresent". See below (also, I changed the assertText to verifyText because, well, I picked the wrong thing the first time. Hey it happens :) ):
A number of these commands are run implicitly when other commands are being run. An example of this is the clickAndWait command. This will fire off a click command and then fire off a waitForPageToLoad. Another example is the open command which only completes when the page has fully loaded.
This next example takes a look at what we need to do to use another AJAX control and wait for the element to appear. Same steps as before:
Fire up Selenium IDE and set it to record.
Click on the load text to the page button.
Navigate to http://book.theautomatedtester.co.uk/chapter1.
Click on the "load text to the page" button.
Wait for the text "I have been added with a timeout"
Note, steps 1 and two are backwards in the book. Not a big deal, pretty easy to figure out what to do in this case. What's not so clear is that the output does not look the same. This is what happens on the page when we follow the directions:
This is what the book says we will see at this point.
and this is what we actually see:
Putting in the waitforText command isn't a big deal, we just need to wait for the text to load, highlight it, and then select the waitForText option from "Show All Available Commands". Except that doing that actually gives us the following:
It works, but for those looking for the values in the original example, they won't show up with the directions as described. You have to enter those values manually, like this:
Hmmm... when running it as depicted, the example fails. Firebug tells us html5div is indeed the value for the div, but it's not responding. This example, however, does respond:
Calling out "id=html5div" explicitly solves the problem. This may just be a difference between IDE 1.5.0 and 1.10.0. I'll check later :).
The point with all of this, really, is to talk about the waitFor* commands, and what they can do. Look through the value list to see all of them.
Storing Elements From the Page
this example demonstrates how you can create variables to store text that appears on a page without actually having to specifically print the string in the test. This one is also a good example because it constructs the test without actually recording it, but letting you access elements and place them into the IDE sequentially.
To see how this works lets work through the follow example:
- Open up Selenium IDE, but don't record this time.
- Start with the base URL of http://book.theautomatedtester.co.uk/
- Click on the first row, In the Command box, type "open". In Target, type "/chapter1".
- Go to the chapter1 page in the Firefox browser, and highlight the text "Assert this text is on the page".
- CTRL-click and select the "Show All Available Commands" menu, and select the storeText option (which has already associated "id=divontheleft" as the target for this action).
- A dialog will appear. In the text box, enter "textOnThePage". This will then be stored as the value for the storeText command.
- Click on the empty row below the storeText command in Selenium IDE.
- Type "type" into the Command box.
- Type "storeinput" into the Target box.
- Type "${textOnThePage}" into the Value box.
- Run the test.
Debugging Tests
There are a few neat little things that you can do to walk through and see how thing will work in your tests. The first is that, if you highlight a row in the IDE, and press the 'x' key on your keyboard, you can execute that single step. You can also click the pause button after pressing play, and that will halt the test at that point, clicking the pause/replay button acts as a toggle, so that you can step through each case (adjust the playback option to get better control of this). Also, clicking on the Find button next to the Target text box will momentarily flash a yellow highlight on the page, showing you where that target is. If the IDE cannot find a target, it will print an error in the log. You can also use echo as a Command and put ${variableName} as the Target to see what the value of the variable is, like this:
Breakpoints can also be enabled at a certain line in the script. to do that, ctrl-click and select "Toggle Breakpoint". This will create a stopping point for your test.
Setting Up Test Suites
Selenium IDE allows the users the ability to go through and set up multiple tests and saving them as a group. To do this, go ahead and create a few different tests:
- From Firefox Menu, select "New Test Case".
- Create a few actions in the table (record them or enter them in directly).
- Click "Save Test Case As..." and give it a meaningful name. Click "Save".
When you have a few tests saved, they'll look something like this:
Now all you have to do is press the Run all button and it will run through all of them in sequence.
What You Can't Record (at least not yet)
At this point, there are some things that record and playback just doesn't work with, as well as interactions that are just not supported with Selenium IDE. David gives us a brief list here:
- Silverlight and Flex/Flash applications cannot be recorded with Selenium IDE.
- HTML 5 is not yet fully supported with Selenium IDE.
- Selenium IDE does not work with Canvas elements (you can't make tests move items around on a page).
- Selenium IDE cannot upload files.
Some of these examples will have ways to deal with them later when we get into WebDriver.
Summary
22% of the books total volume just got covered in this initial chapter! Granted, a lot of that was due to pictures of the IDE and what to see in the screenshots. Still, this is a pretty impressive overview; for the most part, everything as explained works right out of the box. There are some differences in the presentation format and some values, and how the tool responds to them, but again, I think a fair amount of that falls into version differences between what was available when the book was written and what's available now. Also, there's a couple of places where there are small omissions, and these I think fall into the category of "implicit knowledge" (highlighting text to actually be able to access the commands associated with that element. Easy to see once you've done it once or twice.
So far, so good!
End of Section
Michael Larsen, TESTHEAD
Subscribe to:
Posts (Atom)