What A Real Virtual Meeting Looks Like

Jan 29, 2014

I'm part of a distributed team that has daily stand-ups and other meetings, that are all online. Thus, I can't watch this video without laughing my ass off...

https://www.youtube.com/watch?v=DYu\_bGbZiiQ

Spock: Test Framework With Creamy BDD Center

Jan 12, 2014

spock[1]Two things I'm willing to admit:

  1. I think it's a bad idea to dismiss tools prematurely
  2. I think most BDD tools are crap

Delicious hyperbolic contradiction aside, it would probably be more accurate (and PC) to say I've yet to work in a situation where using tools like Cucumber or JBehave would make sense. I.e. these tools just don't compliment my, or my team's, workflow.

Enter Spock. Spock is a testing framework for Java/Groovy, that is very similar to JUnit, but also adds BDD-friendly specification, baked right in. With Spock, there's no need to maintain a separate feature or spec file; no weird broken-English language to learn. Your code is the spec and the end result is clean, readable and maintainable.

Case in point: the following is a Geb test, written in Groovy and using Spock. This is working code from my geb-example project on GitHub.

def 'searches with few results offer nearby results'() {
    given:
    at CLMainPage

    when: 'select category from dropdown and perform search'
    dropdown = category
    searchFor(fewResultsText)

    then: 'nearby results message is displayed'
    at CLSearchResultsPage
    nearbyResults.displayed
}

This test, from my CLSearchTest class, which tests searching on Craigslist (had to use something :) ). With that in mind, the code above is probably very readable to just about anyone. I'll break down what's going on a bit...

We start by defining our test: 'searches with few results offer nearby results', which is also our method name. Method names are string literals (can have spaces).

Next we have Spock's built-in code blocks, labeled given:, when: and then:. These three blocks represent the different phases of a test. Each block can also include an optional description to help with readability. A bit about each block:

  1. given: (optional): Think of this block as a setup. It gives you the optional ability to specify state.
  2. when: (required): This is where the meat of your test code will go. You can have multiple Whens and Thens but they must be used in pairs.
  3. then: (required): This block is for asserts. All code in this section must return true or your test will fail. This gives your reader an easy way to see what the test is actually testing!

This just scratches the surface of Spock's offerings. You of course get a full boat of annotations (including my favorite, @IgnoreRest) and fixture methods, additional blocks, etc... Plus it runs anywhere JUnit runs.

Don't get me wrong, the principals of BDD are sound but I want tools that work the way I do, not the other way around. When using Spock along with Geb's page object pattern and selectors, and Groovy's fabulous syntax, the resulting code is both elegant and readable. YMMV...

Geb vs. Sahi vs. Selenium-Webdriver

Jan 8, 2014

gebAs an addendum to my original post comparing Selenium and Sahi, I offer the same test written in Geb.

Sidebar: I took a bit of flack for the original article, mainly people complaining that my comparison wasn't an apples to apples comparison. Their argument was that because they share a more similar architecture, a more fair comparison would be to compare Sahi to Selenium RC. Of course this argument is complete rubbish. My comparison was (and is) merely a look into the raw code of each tool. But even if it wasn't, Sahi and Selenium both aim to provide the same function: web application automation. Comparing these two tools is completely valid... though I do profess to enjoy the modicum of hyperbole. That all being said, I will paraphrase Mike Watt and say: "if you don't like it, go out and start your own blog!"

Anyway, I'll throw Geb's hat in the same ring with one disclaimer: Geb runs on top of Webdriver... WORLD BEWARE. Please feel free to breath into a paper bag or the something...

Now, without further ado, I give you [gasp] the Google Translate test, written in raw Geb (no developers were hurt during the coding of this test (unless you equate drinking most of a bottle of wine to being "hurt" (which I do not (because I live in Wisconsin)))). Enjoy responsibly!

import geb.Browser

Browser.drive {
    go('http://translate.google.com/')

    $('div#gt-sl-gms').click()
    $('div.goog-menuitem-content', text:'Norwegian').click()
    $('textarea#source') << 'ost'

    waitFor {
        $('span#result\_box').text() == 'cheese'
    }

    quit()
}

Download the working code from GitHub...

Note: this code, like the original Sahi and Selenium code, is "in the raw", as it were. I.e. no page objects or custom methods to help readability/maintainability/*.ility.

Organizing User Data In Your Geb Tests

Jan 4, 2014

gebGeb offers a number of conveniences for writing Selenium Webdriver tests but it draws the line at organizing data. Lacking a sanctioned solution, I rolled my own, making use of Groovy maps (hashes).

Here's an example of how I've been organizing my user data. The following code is a working example (thanks Moodle!) and you can download the full example code from GitHub.

package data

class UserData {
    // user role maps...
    static admin = \[username: 'admin', password: 'sandbox', fullname: 'Admin User'\]
    static manager = \[username: 'manager', password: 'sandbox'\]
    static teacher = \[username: 'teacher', password: 'sandbox', fullname: 'Terri Teacher'\]
    static student = \[username: 'student', password: 'sandbox'\]

}

Pretty simple. I created a package named data, added a UserData class file to it, and filled it with four maps, one for each user our example app.

Then we use it thusly...

import data.UserData
import geb.spock.GebReportingSpec
import pages.MoodleSandboxPage

class MoodleSandboxLoginSpec extends GebReportingSpec {
    static admin = UserData.admin

    def 'login to Moodle Sandbox'() {
        given:
        to MoodleSandboxPage

        when:
        loginToMoodleSandboxAs(admin)

        and: 'if browser window is < 980px, expand navbar button'
        clickNavbarButtonIfExists()

        then: 'assert user logged in'
        // this currently fails on safari because bug in driver and/or moodle...
        loggedInAs.text() == admin.fullname
    }
}

We assign one of the user maps to a static property, admin(line 6), then use that property to log in (line 13), and then to verify we're logged in (line 20).

This approach can really help improve code readability and offers one location to organize all of your data. It can also help with test maintenance, as changes to data need not require updating your tests. This works well for user data but should work with just about any kind of data.

Shmappy Moo Fare!

Jan 2, 2014

101_2066[1]I only have a few traditions with the new year. One is saying "Shmappy Moo Fare", which is how one says "Happy New Year" in drunk. The other I picked up (among other things) when I lived in Nashville. In the south, it's considered good luck to eat black eyed peas on New Years Day.

I recall NOT eating black eyed peas in 2013... rather, I made a split pea soup and hoped that'd cover me. Split peas, black eyed peas... what's the difference. The soup came out okay and that's exactly how I'd categorize 2013: "meh".

This year, I resolved to make a soup with dried/soaked black eyed peas and the whole shebang. The hope being, that it would turn out great, and in turn, prophesise a great 2014.

Long story only slightly longer... the soup was fabulous.

Shmappy Moo Fare to all!

Geb: Get Selected Text From A Select Dropdown

Nov 22, 2013

gebMy current client has decided to migrate their automated ui tests over to Geb, thus, I've been busily ramping up on it for the last couple weeks. Geb, written in Groovy, sits atop Selenium Webdriver and provides some great conveniences, including elegant css selectors and page object support. Additionally, using Spock as your test runner allows you to write your tests in a given/when/then dsl.

I'm finding Geb to be a great tool but like all tools, it has its quirks. Take getting the currently selected text from a select box... Geb does not currently (0.9.2) have an api for this. It has support for getting the currently selected value but you'll have to do a little work to get the selected text. With a little trial and error (heavy on error), I was able to craft a reasonable solution to this problem in a page object selector. Here's my example code...

Page Object Code (TestyPage.groovy):

package pages

import geb.Page

class TestyPage extends Page {
    static url = 'http://madison.craigslist.org/'
    static at = {pageTitle}
    static content = {
        pageTitle(wait:true) {title == 'craigslist: madison classifieds for jobs, apartments, personals, for sale, services, community, and events'}
        dropdown(wait:true) {$('select', name:'catAbb')}
        // workaround for getting the selected text from the dropdown....
        dropdownSelectedText {dropdown.find('option', value:dropdown.value()).text()}
    }

}

Test Code (testy.groovy):

import geb.spock.GebReportingSpec
import pages.TestyPage

class Testy extends GebReportingSpec {
    def 'this is a test...'() {
        given:
        to TestyPage

        when: 'select gigs from dropdown...'
        dropdown = 'gigs'

        then:
        // assert the currently selected text...
        dropdownSelectedText == 'gigs'
        // you can also assert the selected value...
        dropdown.value() == 'ggg'
    }
}

The trick here is in the page object. In the selector dropdownSelectedText, we use .find to get the first option tag, down the dom from dropdown, that has a value of dropdown.value() (in this case 'ggg') and then get the text from that option tag.

Reasonably clever...

Using Page Objects In Sahi (Javascript)

Oct 5, 2013

pageI read a nice post by Martin Fowler about Page Objects, that reminded me that I've not yet expanded on my original post about using them with Sahi. Let me correct that...

To demonstrate using page objects in Sahi, I refactored three tests from Sahi's own demo. You'll find the original three tests in your Sahi scripts folder, in: demo\testcases\training.sah.

Note, that this is my implementation of the page object pattern... I'm sure it could be improved upon. Also note that this code currently only works in Sahi Pro version 5.x. If you're running the open source version of Sahi, you'll need to wait until they update the OS version to 5.x. Feel free to lobby the Sahi dev team to do just that ;)

If you'd like to cut to the chase, you can just download the example code .zip or get it from GitHub.

What Is a Page Object?

A page object is code written to model an actual page (or part of a page) in a web application. Eg. each page in your app, would have an associated page object file that provides the "services" that the actual page offers. Eg. if there's a button on a page in your application, you would have a reference to that button in your page object. If you then write a test that clicks that button, you would access the button through the page object.

Why Use Page Objects?

Page object provide many benefits, including:

  1. Make tests more readable/easier to understand
  2. Make tests easier to maintain
  3. Help organize code into logical chunks

Sahi Page Object Example (Javascript)

The following is the login page object you'll find in my example code.

/\*
    Login Page Object...
\*/
\_include("CommonPage.sah");

function LoginPage() {
    // properties: all accessors and data should be abstracted from tests...
    this.$url = $BASEURL+"/login.htm";
    this.$userTextBox = \_textbox("user");
    this.$passwordBox = \_password("password");
    this.$loginButton = \_submit("Login");

    // helper methods...
    this.go = function() {
        \_navigateTo(this.$url);
    };

    // pass in role array; helps test simplicity and readability...
    this.loginAs = function($roleArray) {
        this.go();
        this.login($roleArray\[0\], $roleArray\[1\]);
    };

    // handle login; allows manual logins...
    this.login = function($userName, $password) {
        \_setValue(this.$userTextBox, $userName);
        \_setValue(this.$passwordBox, $password);
        \_click(this.$loginButton);
    }
}

// extend CommonPage...
LoginPage.prototype = new CommonPage();
// instantiate the object...
loginPage = new LoginPage();

In our example, we first include a CommonPage (more on that in a minute) and then create our page object (Javascript's version of a class), LoginPage. Then we abstract out all the elements we need from the actual page and store them as properties (variables). This is one of the biggest benefits of a page object. If an element is changed in your application, you need only update it's associated property to fix your code.

We then add any methods (functions) we want to make use of on the page. In this case, we simplify the login method by also offering a loginAs method that takes a user role array as an argument. Thus to login (which we'll do a LOT) we need only call: loginPage.loginAs($admin) or in this case, loginPage.loginAs($user).

Next, we extend the functionality of our LoginPage. You may wish to have certain properties and methods available to all of your page objects. You might also have common elements across multiple pages (eg. search box or nav bar). To accomplish this, we use Javascript's prototype object to extend common objects. In our example, we have methods we'd like to make available in all of our page objects. Thus, we have LoginPage's prototype object to extend CommonPage. Now, any method in CommonPage is also available in LoginPage.

Lastly, we simply instantiate the LoginPage object. I do this because I don't care to have a bunch of "new" statements mucking up my tests. Therefore, when I include a page object, it's already instantiated and I can just start using it. This might not jive with some folks... You're of course welcome to instantiate each new page directly in your tests if you like ;)

Testing Login Using LoginPage Object

And now, here's how we use our page object...

/\*
    brian \[at\] qualityshepherd.com

\*/
\_include("../config.sah");
\_include("../Pages/LoginPage.sah");
\_include("../Pages/BooksPage.sah");

loginPage.loginAs($user);

var $currentPageURL= booksPage.getCurrentPageURL();

\_assertEqual(booksPage.$url, $currentPageURL);

Pretty simple. We include our config.sah and the two page objects we need for the test. You'll do this in every test. Then we login using our LoginPage object that we instantiated in the variable loginPage (note the object is uppercase and reference is lowercase). Once logged in, we grab the current page url and assert that we're on the page we expected.

That's it for our login test. The test code is simple and concise... we don't use any Sahi code to access anything on the page, which should make maintaining our code MUCH easier down the line.

There are additional pages and tests in my example code. Feel free to give it a whirl and let me know what you think!