Selenium 2 / WebDriver: Rockin’ Web App Testing

Some Context

In past posts, I have shared my experiences with you concerning how best to use Selenium 1 RC (Remote Control) to test web applications, based on my experiences helping teams. I even wrote a bit of framework code that I shared with you that had helped me and others minimize total-cost-of-ownership of Se test suites. Back when Se RC was one of the very few games in town for page-traversal and DOM-traversal, I found it tricky but workable. I had to write a lot of framework code to keep Se 1 RC Java code as clean as I needed it to be. But it all worked, and I could keep costs contained.

Soooo, a couple of years ago, when I tried using Se 2, I ran into several problems. And I was skeptical about how in the world three different web testing frameworks (Selenium, HTMLUnit, and WebDriver) could be successfully married. At that time I could not, in good concience, recommend to my clients that they use Se 2 and WebDriver. I was afraid that Se had become bloatware. I was afraid that the entire tool was nearing end-of-life.

SE PULLS OUT OF A NOSE DIVE

Well, I’ve been using Se 2 and WebDriver (NOT Se 2 RC) recently (in Java), as I work with Josh Kerievsky and others at Industrial Logic to develop a Selenium 2 album and workshop, and I am here to report to you that as far as I can tell, Se 2 / WebDriver rocks. End-to-end testing with tools like Se are still, in my opinion, testing options of last resort, for reasons I covered in another old post (in short, NEVER use Se to test ANYTHING you can test more affordably with another automated testing tool). But Se 2 / WebDriver in its current incarnation (I’m using selenium-server-standalone jar 2.32 as of this writing) is indeed a whole new ballgame, and deserves more attention, more traction, and more respect in the Web App testing world. Let me summarize.

In With The New

Se 2 is a marriage of Selenium, HTMLUnit (which years and years ago invented the notion of PageObjects, very quietly, simply as a matter of good OO practice), and WebDriver (which is very strong at automating browsers natively, from the operating system, in whatever way a particular browser wants to be controlled by a particular OS version). And in my recent experience, many things that used to burn me about Se RC and Se testing generally are now either way easier, or completely fixed in my current version of Se 2.

The OLD WAY: UGLY SE 1 CODE

Let’s see an example. Selenium 1 Remote Control (RC), when I asked it questions, returned me primitives: integers, strings, booleans. These primitives are all about “how to get lots of stuff done, no matter how confusing that is to try to figure out later.” Here is a classic, old-fashioned, crappy Selenium 1 RC test, with Se calls in-line in the test code (Java in this case):

Few people ever recommended writing Se RC code like this, but too many programmers, testers, and teams wrote (and still write) Selenium RC code exactly this. There are many problems with this code. You cannot easily tell what the code is doing (in terms of the app being tested, much less its problem domain). And most of us in the Se world have seen much worse code than this, sad to say. But the main thing here, for our discussion, is that you cannot tell easily WHAT pages are being traversed, and WHY they are being traversed (for functional testing purposes). You cannot tell WHAT the test is doing. Also, the mechanics of waiting for pages to be available is embedded in the tests. As I’ve covered elsewhere, you can do a lot of things to clean up code like this. And you shouldn’t have to do so much work.

AN OBJECT ORIENTED API

Let’s hear it for a good old-fashioned Object Oriented API, in which, when I ask a framework object a question, I get returned to me a true object that skillfully encapsulates just the behavior and state I require.

These days, I’m mostly writing Se 2 / WebDriver code that looks like this:

No, I am not employing any PageObjects here, because I have not needed to. I did have to home-grow a bit of frameworkie-code to work around occasional StaleElementReferenceExceptions that too-frequently crop up when testing Ajax-rich apps in which jQuery does a lot of attaching, detaching, and re-attaching elements to the DOM. Yes, WebDriver should provide a driver-configuration API for, perhaps, returning only elements that are NOT STALE, since they are useless. This would impose an ambient load on all element-locating findElement(By …) code, so a nice complement would be an explicit as-needed call to something like findElementOnceFresh(By …). Meanwhile, I am using this workaround, adapted from various ideas on the interwebz:

This is illustrative. My point is that in the arms race between web-app-testing frameworks and internet application richness (great gobs of good, bad, and ugly legacy JS and jQuery, much of it un-microtested), workarounds are still inevitable.

But with Se 2, I am writing cleaner code, faster and easier. And so far, I am rolling my own PageObjects much less frequently, since WebElement objects are very handy right out of the box.

More importantly, Same source origin policy workarounds (proxy servers), and other issues resulting from Se 1 driving the browser from within the JS sandbox, are overcome entirely by Se 2 / WebDriver, which drives the browser natively from outside, in whichever way a browser/OS permutation prefers the browser be driven. This is huge.

So I am doing more with method extractions, so far, and less with entire framework classes. Since test code is not production code, and functional test code can be exceptionally expensive to maintain, less code is a very good thing.

I’ll keep you updated. But I’m going to get to know Se 2 / WebDriver really, really well.

 

 

Whack-A-Method

I Feel a Framework Coming On

[Agile Programming: Lesson One, Part Four]

I’ve been pitching to the world this notion of a gradual ascent into programming excellence, starting with just a bit of refactoring the innards of classes in a small problem space, and just a bit of test-driving in the same problem space.

I ask people to do the exercises, keeping methods really, really small, and really simple. But up until now, if someone asked, Got a Test for That?, my answer, sadly, was No, Sorry, Use Static Analysis Tools – There Are Tons of Them Out There. Lame answer.

Inspired (again) at a recent CodeMash by another whack at the excellent Ruby Koans, and having heard great things about similar Scala Koans, I wanted a koans-ish learning tool for refactoring. You know what’s cool and fun about these koans? Everything, that’s what. Learning should be fun. Yes, that’s right. You heard it here first. These test-based koans are super fun.

When I asked people to keep methods under some number of lines of code, and under some cyclomatic complexity threshold, I Wanted a Test for That. And now, indeed, I do. I have two Whack-A-Method exercises; one for refactoring a sub-optimal implementation of BankOCRKata, and another for continuing to test-drive a pretty-good-so-far partial implementation of the BankOCRKata. The first exercise has a couple of really Eager end-to-end tests, but Hey! They give you 100% Code Coverage! Yay for anything!

So, these are Eclipse projects. If you have Eclemma installed, then you can pull down Coverage As > JUnit Test, and behold: you see your code coverage, of course. And in either Whack-A-Method exercise, you see the results of the tests for current production code behavior, AND YOU ALSO see results of tests that automagically recurse through your output folders for .class files, and ask a little jarred-up, embedded static analysis tool called CyVis (Tx, Guys!) to instantiate a test case for each of your classes, and instantiate a different test case for each of your methods.

Because I used the Junit 4 built-in parameterized test runner extension, you don’t get much info from the tests that run green, and you cannot (at least as yet) click through ugly classes or methods in the failures (though I’ve provided meaningful failure semantics).

But Hey!  It’s totally version 0.1, and it works OK.

Caveat Lector: Yes, We are Refactoring on Red

So, in the real world, you never want to refactor on a red bar, because you cannot tell whether you are screwing up existing behavior.

And, on the other hand, in the world of koans and learning tools, tests are an awesomely addicting, engaging learning mechanism. So, friends, consider this current Whack-a-Method a proof of concept. It’s easy to try, requires no installation, works right outa the box, and is fun.

But you must indeed distinguish between red bars in the tests that cover the production code, vs whackAmethod red bars. In this pair of exercises, it’s OK if your whackAmethod tests are red while you refactor. The other tests are saving your bacon with respect to code behavior. It’s not OK if those non-whackAmethod tests are red.

Of course, you are heading toward a green bar. And you want to get there as fast as you can, and stay there as much of the time as you can.

And ultimately this tool is likely to become plugins and extensions for editors like emacs and eclipse. Not because the world needs scads of additional source analysis plugins, but because most of them are as simple as a Saturn V rocket, and this one is dead simple. And for now, as I’ve said before, you really only need a couple of metrics.

Whack-Extract Till Green

In the refactoring Whack-A-Method exercise, you just keep extracting methods and classes until everything runs green. Easy? Try it and find out!

In the TDD Whack-A-Method exercise, you just keep test-driving your code till you have fulfilled all of the requirements in the Requirements.txt file, and you keep all the tests green as much of the time as you can.

Tweak the Thresholds, Once You Know What You’re Doing

You can tweak the constants in CleanTestBase.java to tighten or loosen the method/class size and complexity thresholds. But please don’t at first. The defaults help learning to happen.

Does it Eat its Own Dogfood?

Yes, it does. All the classes in the whackAmethod package are themselves fully Whack-A-Method compliant, given the default thresholds. Let’s see a plugin do THAT.

A Bit of 0.1 Framework Fer Ya

So, if you want to try this experiment on any Java codebase of your own, you totally can, with minimal copy, paste, config (well, as far as I know today — again, version 0.1).

  1. Copy the entire whackAmethod package from my test source-folder to your own test source folder. (If you want to refactor my source, go for it, lemme know, and I’ll likely give you commit rights to the project).
  2. Copy the cyvis.jar and the asm-all-2.1.jar to your project and build path.
  3. Change the constant STARTING_DIRECTORY_NAME in  RecursiveClassFileFinder.java to point to the root of your output folder (it currently defaults to “bin”).
  4. Run the tests. The Whack-A-Method tests should all run.
  5. Contact me with any problems.

OK, Now Let’s Discuss Microtests & TDD

Agile Programming: Lesson One (Part Three)

At the start of this series of posts I suggested that those who really, really want to become Agile Programmers start with a couple of refactoring exercises. In another post I explained why I suggest this as a starting point. I’ll reiterate here that I am suggesting that you perform those exercises several times, several ways, before you attempt the exercises coming up next.

All done?  OK. Cool. Now, three posts in, I’ll introduce the ideas of microtests and Test-Driven Development (referring you to other sources for deeper dives into these large topics).

If you have been following along in code, as well as in your reading, you may by now have discovered and learned several things. Here are a few, any one or two of which may have occurred to you:

  • You would not really be safe trying to do those original refactoring exercises without the handful of tests that cover them.
  • It’s not hard to break existing tests if you keep running them after each little refactoring step
  • The refactoring steps in the exercises can be pretty hard to do, even in those really small amounts of code.
  • As you extract behavior into lots of new methods, and perhaps into a few new classes, it would be really cool to have new, separate JUnit tests that cover those specific little behaviors.
  • It can be tricky trying to determine how to keep test code itself clean and concise.

I suspect that after enough repetitions of those first exercises I suggested, one or more of these does occur to you. Let’s dig into testing in the context of these kinds of observations.

Definition: Microtests

By Microtests, which term was coined by Mike (@GeePawHill) Hill, I mean the same thing that people like Mike Feathers and J.B. Rainsberger (and many other TDD thoughtleaders) mean by unit tests or isolation tests or programmer tests. So in Java, a JUnit test is a Microtest if it:

  • Tests a single discrete behavior/responsibility (“in isolation”)
  • Runs completely in memory: does not touch databases, GUI frameworks, file systems, or networks. Those other tests are frequently useful, but they are not microtests.
  • Runs really, really fast. Fast enough means somewhere between 10 and 100 per second, or faster.

Vital Ends: Enough Microtests for a Production Codebase

Every production codebase desperately needs to have enough microtest coverage.

Your codebase has enough microtests if your code coverage (as previously discussed) is at least 85%, and your median test-method length and production method-length is really small (as previously discussed), and each test class and test method is itself SRP-compliant, and very experienced microtesters have looked over the entire test suite and pronounced it healthy.

There are leaps of faith for you to take here, admittedly. And that last clause is really fuzzy and subjective. I get it.

Nevertheless, I’ll emphasize this:

Aside from the production code itself, there is no more important artifact for any codebase than its suite of microtests. A codebase without enough microtests, as Feathers has pointed out, is by definition Legacy Code. Agile Programmers are careful about microtests the way veteran skydivers are careful about packing parachutes.

Again, an exhaustive suite of microtests are ends, worthy in their own right, for protecting us from introducing defects when we change code.

But as is very frequently discussed in agile circles, Test-Driven Development (TDD), as a means to those ends, is important in other ways.

Definition: Test-Driven Development (TDD)

Test-Driven Development is the practice and craft of writing tiny little microtests for production code before you write the production code itself. The practice has been covered exhaustively in other sources, so I’ll only sketch it here, starting with its benefits. Again, prepare to make leaps of faith:

  • TDD is the most efficient, least-expensive way to produce high-ROI, low-TCO suites of exhaustive microtests.
  • TDD is the most efficient, least-expensive way to drive production code in the direction of high-ROI, low-TCO Clean Code.
  • TDD and microtesting have layers of sophistication, auxiliary practices and techniques, and otherwise a world of richness of their own.
  • Skilled TDD (and refactoring) completely change how you feel about programming, for the better.
  • Only after you have written a few thousand microtests using TDD (and other practices) do those first four points above become experientially clear.
  • For many programmers, TDD seems at first (perhaps for months) to be a maddening, fanatical waste of time. It feels (to some) like walking backward up a staircase, blindfolded, carrying a tray of expensive flute glasses full of expensive champagne. Senseless, in other words. But that does pass.

Yes, you can write tests last, after you have written production code. But in exercises coming up soon here, I hope to provide you an opportunity to learn that this slows you down more than you can tolerate. I’ll also explain why that seems to be true.

One more thing: it can be very, very difficult to do real TDD, or to add or change code at all, in existing codebases with very low code coverage. Before continuing with this post/lesson, if you doubt what I just said, please consider attempting this exercise I created a few years ago. Then come back here and continue.

The TDD References

First, the references. TDD basics are covered on-line pretty darned well. The more advanced, sneaky design mechanisms behind it are covered (for the advanced reader) here and here and here and here.

Aside: My fave, fave intro to TDD online is @JamesShore ‘s “Let’s Play” series. James models to us all expertise, poise, fun, and best of all, supreme openness and vulnerability. Also the desire for a pair! You can follow these videos and learn enormous amounts (the pace of learning is different from what I am attempting here — it’s OK if you find yourself lost by him pretty fast; if you revisit these next year you likely won’t be). You can also hear his cat whining about TDD in the background, if you listen carefully.

In all seriousness, in the opinion of some, James dives quickly into “TDD by the book,” which is to say with very, very little up-front design. Note that, as James proceeds, given his level of skill, this is not a serious problem for him. Master that he is, he can refactor himself out of any design misstep. This is not TDD at a novice level. Also notice in this series of videos how deeply James dives into mastering the problem domain at hand. It is his deepening mastery of that domain, coupled with his TDD mastery, that allows his design to emerge in increments that might at first seem ungainly, but are in fact elegant.

TDD is also covered in a slew of great books. Good ones in Java include (at least)

No, you need not purchase and read all of these books. Any one of them is likely sufficient to challenge you with Java TDD exercises and thinking for some time. And you need not purchase any of them this minute. But you will need at least one of them soon, both for tutorial and for reference. There is a completely different slew of books for  test-driving in other languages, BTW. [More later.]

The Classic Red-Green-Refactor TDD Cycle

The classic TDD cycle is covered well, in all seriousness, in the wikipedia TDD write-up. When you are learning TDD, taking this grand leap of faith, stick to this cycle like glue. Follow it blindly for a good long while. Internalize it.

If you need a little humor to keep you on track, you can use this handy on-line “pair partner” to remind you where you are in the cycle.

A New Rule to Follow in Our Challenges

We’ve been working in the BankOCR Kata for awhile now. We’ve been refactoring existing code. As we go, we’ve been adhering to certain rules (paraphrased here, for our next challenges):

  • Keep all tests running green as much as possible. Also try to purposefully break them sometimes, to see what kinds of coverage they give you in the code (more on that later, too).
  • Rename each entity (project, package, class, method, variable) at least twice, as you learn more and more about what it should be doing
  • By the time you are done, no method should contain more than 8 lines of code (this also applies to test methods), and most methods should be in the neighborhood of 4 or 5 lines of code, including declarations and return statements. This includes test methods.
  • Don’t let code coverage fall below 85%.

As we switch to test-driving brand-new code, the rules above still apply. To this I’ll add a new rule, for the test-driven code:

  • Test-drive classes that contain only a single public method, no more than 3 fields, and no more than 4 private helper methods. Try to avoid accessors (getters and setters). Can you avoid them? If not, why not?

Your Next Challenges

Start by ignoring the design you have been working with in the first exercises. Empty your mind of design ideas for the BankOCR Kata. Start with this new, nearly fresh version of an implementation, which can now help you with the special love provided by the Whack-A-Method testing mechanism.

Try test-driving just one part of the BankOCR Kata at a time, and in this order (for now):

  • Test-drive code that parses  a bunch of raw OCR-like String data (represented however you like) into separate OCR digits. Remember the input data looks like this:

  • How many classes does this need?  I mean, if they are really, really small, SRP-compliant classes?
  • Next, test-drive code that converts those individual OCR digits into integers. Again, how many classes do you need? How do you know?
  • Finally, test-drive code that converts groups of those OCR digits into proper account numbers.

Now, after having done that the above way, throw away all the code, and do it in reverse. Is that harder? Easier?

Remember to follow all of the above rules. And stay tuned, next, for some more deep dive into emergent design: the magic thing that happens as we begin to master TDD, Clean Method Hierarchies, and Clean Code generally.

Selenium RC Patterns: Links that, uh, Go to Pages

[Part of a series of posts on Java Selenium RC patterns I find useful.]

In the last post, we looked at self-verifying PageObjects: Java classes that are “testable representations” of a web app page, and that automatically verify for us, on instantiation, that we have indeed arrived on the actual web page we intended to.

So how do we handle page flow? I’ve handled it numerous ways in the past. I don’t like any of them anymore. Ultimately what I wanted, and now have, is something that mimics the way an actual <a href></a> takes you to a new page: classes that represent html links that, when clicked by Selenium, take you (predictably) to new PageObjects or pane objects. So the Selenium RC Java mechanics for page flow are no longer cluttering the test code, nor, in fact, the PageObjects.

Instead, I use what I call ElementObject classes. PageLink and DhtmlLink classes, in particular, behave like little Factories. When instantiated, these objects are told which PageObject to instantiate when Selenium “clicks” on the actual html links those classes represent. Whew!  Confused yet? Let’s see some code, starting with a package structure, and let’s explain ElementObjects more generally.

Background: ElementObjects

ElementObject package structure

util.elements package structure

Above are the ElementObject classes I use, in HTMLUnit style, to represent discrete  html element varieties and their behaviors.

(Note: The introductory post in this  series tells you how to get all of this code. If you have the code, explore this little object tree, starting with the abstract BaseElement class. Explore how different pages and panes use these element classes.)

Let’s tour a slice of the BaseElement tree briefly. Here is the abstract BaseElement class:

So all elements, since they extend BaseElement, have locators (which are all CSS selectors, as discussed in the previous post). The isPresent() method (using the conventional Selenium isElementPresent() method), uses vanilla Selenium to reveal whether any element is indeed present in the browser’s representation of the HTML, rendered (usually) by a real HTTP Request/Response cycle. Similarly, isVisible() reveals whether  an element is “visible” after any dynamic call that does NOT involve a real HTTP Request/Reponse cycle. Under the covers, isVisible() uses jQuery to check visibility in the in-memory DOM. The short answer to “Why have both?” is that isVisible() is heavier-weight and slower, but usually works when isPresent() does not. The even shorter answer is that browser manufacturers hate each other, and sometimes ignore the w3c, but they all standardize on jQuery.

So, for example,  ClickableElement extends BaseElement, and adds just a predictable smidgeon of clickable-ness:

And further down the tree, a CheckBox gives us the ability to check a checkbox, or if it is one of those fancy graphical checkbox simulacra, we can just click() on it using the inherited method in ClickableElement. Either way, we have checkbox-looking things covered.

Notice all of the static method calls to BrowserDriver.java. We’ll cover him in deep detail later, but he is our Decorator/Facade for Selenium and jQuery calls. It provides singleton access to DefaultSelenium and several of its useful methods, as well as several convenience methods we have found useful.

The point here is that only down at the ElementObject level does our framework “know” about BrowserDriver, and the nuts-and-bolts mechanics of getting Selenium (or whatever frameworks we want) to do stuff to real web page elements.

And of course the most essential point is that in our PageObjects, we can represent every HTML element as one of these types, keeping the test framework code nice and DRY.

In general, this is how the ElementObjects work. Caveat Lector: I don’t have a full, complete set of these in my sample code; I have the ones I have been using all the time. Feel free to extend this package as necessary (and to send me your contributions).

PageLinks and DhtmlLinks

Now the meat of this post: how do we get from page to page?

First let’s look at how a PageLink client uses it for a field on a PageObject. Let’s look at a test for creating a Task in FatFreeCRM:

Note in the setUp() method that we get to a TasksPage by clicking clickToNewPage() on the tasks field on a MainNavigationTabsSet class, which looks like this:

Note that tasks field is of type PageLink, parameterized with a class. And notice that when you instantiate a PageLink, you call a PageLink.create() method. Between these two things, we ensure that when we ask Selenium to click on that tasks link, we end up instantiating an actual TasksPage PageObject.

It’s a smidge confusing, perhaps. Bear with me. Here is the PageLink class:

Notice that PageLink extends ClickableElement, so whatever element a PageLink object represents, we can click on it. Yay! Notice also that when we instantiate PageLink, it expects a css locator.

Most critically and cryptically, notice all the Java generics magic, which can be confusing Java syntax to many programmers. The upshot is noisy framework code, but it keeps explicit casting out of the test code. It keeps the test code very simple indeed.

Now notice what happens when a test method calls the clickToNewPage() method: first, we click on ourselves (which will, if you look at click() in ClickableElement, get BrowserDriver to click on the locator we were instantiated with. Then the tricky bits. We call clickToNewPage(), which asks BrowserDriver.waitForPageToLoad() to let us know when the new page is done loading. Because Selenium can tell when a real HTTP Request/Response cycle is done, this will work for real pages with actual, different urls.

Then, aha! Our little Factory method uses a little lightweight Java Reflection to construct and return us an instance of that PageObject whose Class we passed in on instantiation. In MainNavigationTabsSet above, you can see that the tasks PageLink is declared and instantiated with TasksPage.class. So indeed, a self-verifying TasksPage PageObject gets constructed and handed back to test code when that test calls Common.mainNavTabsSet.tasks.clickToNewPage().

So a bit of Java design forethought gives us this ability to click on a tasks link, and proceed without further ceremony to a TasksPage. Our page flow does, in fact, much mirror the HTML and pages in the production code.

Our test code (above) is, again, succinct and expressive, and only a link to a page need know how to get there. Just like in real life.

Similar to PageLink, DhtmlLink provides us a little factory for dynamic html behaviors (clickToNewContainer()), whether they have Ajax-like server conversations, or just change the html in the browser. In this case, because we don’t have a real HTTP Request/Response cycle, we don’t call waitForPageToLoad() on Selenium. Selenium has no idea whether the “page” or “pane” we need is now visible. Our PageObjects take care of that. We just click(). Like PageLink, DhtmlLink uses much of the same Java generics gobbletygook to keep track of concrete Class types to be instantiated at our request. In this case, the base class is BasePane, not BasePage:

Next up: what the heck is this BrowserDriver thing, and how might we use it?

Selenium RC Patterns: Self-Verifying Page Objects

[Part of a series of posts on Java Selenium RC patterns I find useful.]

What we Want: Expressive, Succinct Tests

Let’s say I want to test that I can log into an app. I want my Selenium RC Java test code to look something like this, because I want it to read, aloud, the way I would describe actually logging in and checking that everything went mostly OK:

Several techniques make this possible, but the one we will focus on in this blog post is the notion of a self-verifying PageObject, which is essentially a “testable representation” of an actual web app page we wish to traverse, manipulate, and test. So my LoginPage class, above, allows me succinct manipulation of the corresponding login page in the system under test.

Note that this test knows nothing about Selenium. Indeed, neither does the LoginPage class (below). More on that later. Note that this test does not include any waitUntilPageIsFrickinLoaded() calls, nor (worse) Thread.sleep() code, and very little direct instantiation of PageObjects. The page flow mechanics is encapsulated elsewhere. Note also that as I go from page to page, I don’t explicitly assert that I got there. I shouldn’t have to. My test should be able to take that for granted. It turns out that assertions are being made under the covers about having arrived successfully on intermediate pages, but that code is abstracted away. That’s what this post covers.

The only useful assertion in the test proper is that, once I have logged in with proper credentials, I arrive safely at the homepage (and even this assertion in the test is redundant, and included here only to reveal intention; the DashBoard page is also self-verifying).

Glance-Readability

A test as short and expressive as the one above passes the “glance readability” test. Anyone familiar with automated testing semantics, and the biz language of this CRM domain, ought to be able to grasp what this test does at a single glance.

Suffice to say, we want our Selenium RC tests, as much as they can, to be this succinct. And, again, that requires that they stick to expressing page traversal and manipulation in the local biz-specific language of the web app’s business domain. So, finally, let’s see the under-the-covers page self-verification mechanics.

PageObjects as I Use Them

The selenium-rc-patterns sample Java codebase that illustrates all of the patterns in this series of posts talks to a localhost copy of a Rails project called Fat Free CRM. If you want to learn a bit about this app, you can play with a hosted sample version here (you have to sign up for an account first, which is easy).

This CRM system has discrete web pages like a Dashboard (home page, essentially), and pages for Tasks, Leads, Campaigns, Contacts, Accounts, and Opportunities. For each of these actual, production pages, my selenium-rc-patterns Eclipse project contains a matching PageObject with methods and fields that provide access to the services on that page.

Above, when you ask an instance of a LoginPage to login(username, password), then the TextFields and PageLink type know how to return us a PageObject that should then be cast to a DashboardPage and returned. (More on that in another post.)

Selenium RC developers have been using a PageObject pattern for awhile. The pattern dates back, at least, to the original HTMLUnit, whose API rather strongly encourages you to represent your pages under test as extensions of what it calls an HtmlPage. I don’t use Se 2 yet (might someday, might not), so I don’t use its PageFactory pattern.

Instead, I use my own PageObjects that extend a BasePage (or BasePane), partly so that I can control how and when PageObjects are instantiated, and verify automatically and ambiently on instantiation that Selenium is indeed on that page. Again, that’s much of what keeps the above test code so simple: I’m not explicitly waiting for a page to load, and I’m not asserting all over the place that I’ve successfully arrived on a given page.

So, my LoginPage class has a login() method that accepts a username and password (we’ll cover the return types of these fields and methods in another post that describes how page-flow works):

Verifying That the Production Page has Been Loaded

The real point of my flavor of PageObject pattern is the self-verifying bit. Let’s dive into that — not later, but now.

Note that each of these PageObjects extends BasePane, and has a PAGE_IS_LOADED_CSS constant:

In the LoginPage constructor way above up there, you can see we first explicitly call super() on BasePane. Here is BasePane:

You can see that this constructor calls waitUntilLoaded(), which makes a static call to a method on our BrowserDriver (the Facade / Decorator that handles all of the actual Selenium calls) in order to loop until our LoginPage (in this case) actually is loaded. The argument supplied is the result of calling getPageLoadedCssLocator().

But wait! That’s an abstract method! So Yes, we have something very like a template method pattern here in waitUntilLoaded(): the concrete implementation of getPageLoadedCssLocator() on LoginPage returns that PAGE_IS_LOADED_CSS constant String.

Deep, deep under the covers, the BrowserDriver.waitForElementIsVisible() method looks like this:

We’ll discuss the BrowerDriver class at length elsewhere. And we’ll also discuss the injectJqueryIfAbsent() method, which we hope an upcoming Selenium RC release will obviate.

The upshot of the waitForElementVisible() method and the LoginPage and BasePane code above is that the LoginPage object will not successfully finish instantiating until Selenium can successfully verify that a unique element on that page has been loaded. In other words, once a LoginPage instance is loaded in memory, we actually are on the LoginPage, by definition, as long as that CSS element selector syntax is correct. Voila, automatic, ambient page flow assertion.

This is much of how we get our test methods so succinct. The PageObjects take care of verifying for us, at instantiation, that we have safely arrived on their corresponding production app web pages.

Caveat Lector: there is a flaw in my code I have yet to squeeze out:  duplication between a BasePane, used above, which I usually use for dynamic changes in the HTML, and a BasePage, which presumes that a real HTTP Request/Response cycle has occurred. I will collapse those two together shortly.

Next: we’ll talk about reusable HTML Element objects, and how the linkish ones know, in my code, how to return the PageObject we wish to traverse to next.


Selenium RC Java Patterns: Watch this Space

My opinion about through-the-web-GUI enterprise-app-testing, in general, is that it is like driving on ice in a blizzard: not something you want to do lots and lots of, because sooner or later you’ll get into deep trouble. But given your context (living in MI, for me), driving on ice in the snow is something that is useful to know how to do well, in a pinch.

I’ve blogged in the past about low-TCO (Total Cost of Ownership) Selenium RC testing in general, and about  how much of your automated testing budget should be allocated to different kinds of testing at different points in an agile transformation. Of late, I have been helping teams learn to use Selenium RC, in Java, to test web apps through their GUIs. Once the above Caveat Tester is spoken, I help them do the Selenium RC testing that they feel they MUST do as well as possible.

I have been diving more deeply into it for several clients recently, and finding and refining some useful patterns I had not needed or found before (with the help of several colleagues). And, admittedly, some of what I am doing is refining my old patterns in response to things like Refactoring pressure. In general, I am devising increasingly DRY Object Oriented Selenium RC Java patterns. I recently presented on them at Agile 2010.  Using git, you  can checkout the code that illustrates these patterns from github here.

I intend to share each of these patterns with you, each in its own blog post, in coming weeks.

So watch this space for blog posts covering the following topics:

The code I link to above illustrates all of these patterns, expecting (for now) to run against a demo instance of a Rails app called FatFreeCRM, which is available for you to play with at http://demo.fatfreecrm.com/login.