Domain Based Web Testing

Domain based web testing is a style of writing and organizing testing scripts so that they can:

This is crucial especially for a large scale web application.

Example

Domain based web testing focusing on the intent of the test rather than the action of the test.

Watir Style

The simplest domain based web testing wraps the browser object (the one that provides the API to drive the browser) into a page object that provides API that returns the HTML element object based on what you can do at the current page. This is the style that watir provides. These HTML element object classes are simply wrappers that wraps the action command and delegate to the browser driver class as action based command.

login_page = LoginPage.new(@browser)
login_page.username_field.enter('user')
login_page.password_field.enter('password')
login_page.login_button.click

Page Object with Behaviors

When the user comes to a page, they normally wants to do a certain task that involves a group of actions. The page objects should provide those APIs so that the test is clear on what the test is doing rather than how it is doing it.

login_page = LoginPage.new(@browser)
login_page.login('user', 'wrongpassword')
work_items_page = WorkItemsPage.new(@browser)
work_item_page.fill_in(data_fixture.create_full_work_item_data)
work_item_page.due_date_field.enter_yesterday
work_item_page.submit_buttoc.click
work_item_page.should be_present
work_item_page.error.should be_visible
work_item_page.error.text.should == 'Due date should be after today'

Benefit on Testing Quality

Domain based web testing requires extra work to design and implement the page and HTML element objects. However, experiences have shown that they pay off quickly.

With the shared code, each tests only need to write the code that is special about the test. This makes it easy to understand the tests and maintain them. For example, with each page provide the way to locate the HTML elements on the page, it is easy to find the code and change it when the element id or name changes.

The following are the patterns that have been proved to be useful. Try them out and see if they are useful to your project as well.

Shared Steps

You can wrap common steps into the behavior of the component (page or HTML element).

For example, you can create the login method on the login page. This method will enter the user name and password, click on the submit button and make sure that the login was successful. You can even create different user on the fly and login as the user so that different tests will work on different sets of data and won’t affect each other.

Widgets

Some HTML element does form submission upon change automatically and some doesn’t. You can design your HTML element object so that it knows when the value changes, it needs to wait for the page load.

Some HTML element has Javascript associated with it so that some other part of the page will change, even when there is no page load. You can also design the element to wait for the condition. For example, for a check box that shows and hides a comment filed, it can be designed as following:

class CommentCheckBox
  attr_reader :browser, :locator

  def initialize(browser, locator, comment_span)
    @browser = browser
    @locator = locator
    @comment_span = comment_span
  end

  def selected
    browser.get_value(locator) == 'on'
  end

  def click
    old_value = selected
<<<<<<< HEAD:site/doc/example.rb
    browser.wait_for_condition(@comment_span.script_check_visible((not old_value)), 5000)
=======
    browser.wait_for_condition(@comment_span.script_check_visible(not old_value), 5000)
>>>>>>> a3598e23fd3d746137b3a82b575d68ed060b1d4b:site/doc/example.rb
  end
end

In this way, the test code will remain the same and all the work that making sure the test dose what it intends to do is encapsulated into the place where it should be.

Speed Up Data Setup

It is always best to exercise the web application during the tests. However, for a large application with lots of tests, it might not be feasible to run everything through browser. You would still want each page to be fully tested but for some of the tests, it is a good idea to create the test data directly into the database. This will speed up your tests and give you better test coverage.

With the domain based web testing, your tests only concentrate on what kind of data to generate and delegate the generation detail to the page objects. When performance becomes a concern for your tests, you can add additional behavior on those page objects so that for most of the test it delegates the data creation to a back-end API that inserts the data directly into the database.

Benefit on Communication

With your domain based testing code expressing the intent of the test, you have created a “domain specific language” for testing of your web application. It would not be hard to go from here and match that language to your domain language. For detail on domain driven design, see Domain Driven Design