Integration Testing with Selenium

Testing.  Testing.  Testing. There any number of ways to qualify testing in software.  Unit testing.  Functional testing.  Systems testing. Integration testing.  Usability testing.  Load testing.  Et cetera.  And what testing you do do, or do not, is somewhat predicated upon the type of software you are developing.

One thing is for certain, though; no matter the domain the interface is always key.   Kotoba is no different.  We have been doing a lot of exploratory technology development with only the bare-bones paid to sustainable (read automated) testing.  While we have it, we can always have more.

One area where automated testing can be a real chore is at the user-level.  This is more than just calling back into our application using URLs as is often done at the functional level; we really want to, as best as possible, mimic the user experience as if we are the user. And while we could do this manually, it is replete with tedium and errors. So how do we automate this step in our quality assurance?  Que Selenium; a power tool that uses JavaScript to test our application in any browser that supports JavaScript. It even has its own “IDE” that allows you to record events that then can be saved as Selenium tests. More to boot, Selenium is supported by a number of languages and frameworks; albeit, we are mostly interested in Selenium on Rails.

Over the weekend I spent time understanding how best to integrate Selenium into Rails. Out of the box Selenium is ready to go but for one thing: user login. Kotoba uses hashed passwords with a temporally sensitive salt to help ensure user passwords are secure. Unfortunately, this makes our life a little more difficult in part because Y(a)ML test fixtures do not go through ActiveRecord, but create SQL statements directly. Which means that all our model instance methods that help create our secure password are bypassed.

More specifically, whenever we run Selenium setup while our user accounts are created, they are done without passwords. Consequently, we need a way to attach passwords once the accounts are created. Unfortunately, Selenium provides no known callback mechanism to provide model/application initialization. While I explored implementing this callback mechanism, it become apparent that doing so would be not much than a hack without some concentrated engineering. Additionally, we must remember that Selenium tests our application using JavaScript. That means that while we can include Ruby in our RSelenium tests, these are only run the first time the test is read in by Selenium while Selenium generates JavaScripts calls that it then uses to run the tests. To wit, the next time is run these ruby calls are not made.

Imagine I have something like:

  1. Setup app; clean fixtures: Javascript
  2. Setup passwords: Ruby
  3. Login: Javascript

On the first pass we clean our database, create our fixtures, set our user passwords and create our login test.

However, the moment we actually run our test we do everything but set our user passwords. The result? Our test breaks.

Our solution is to create a controller that includes initialization methods. To ensure that these controllers and methods are never called in anything other than test using a before_filter.

class InitializeKotobaController < ApplicationController

  before_filter :verify_environment

  def a_method
  end

private

  def verify_environment
    unless ['test'].include?(RAILS_ENV)
      raise "This controller cannot be used in this Rails environment [#{RAILS_ENV}]"
    end
  end
end

From our Selenium test, we can call open, or:

open('/initialize_kotoba/a_method?param1=a&param2=b')

Note how we are able to pass parameters into our controller allowing us to make it as versatile as we need it for our tests.

While you can use partials in our tests, this makes our tests a little less accessible to the average tester. Ideally, we want to be able to hand over our integration testing to someone who is more focussed on the user experience than the inner-workings of our programming environment. While arguably not a concern with Kotoba, it is nevertheless a philosophical one I prefer to strive on all my projects.

The solution is to include your own DSL (domain specific language). This is not as difficult as it sounds, nor nearly as cutting-edge as some blogs might make it seem. In reality, many DSLs s are really nothing more than a API that is catered to better mimic the business domain's lingua. The below is no different.

# Include our own Selenium DSL functions
config.after_initialize do
  if SeleniumOnRailsConfig.get(:environments).include? RAILS_ENV
    class SeleniumOnRails::RSelenese
      class_eval do
        include Selenium::DSL
      end
    end
  end
end

Then we add a file at $RAILS_ROOT/lib/selenium/dsl.rb

module Selenium::DSL

  def login(user, password)
    # include our RSelenium tests here
    open('/')
    assert_title('Kotoba « Accounts « Login')
    assert_text('login_legend',I18n.t('login.title'))
    type('email', user.email)
    type('password', password)
  end

end

Now we can just call

login(user,password)

from our RSelenium tests to automatically login as a specific user.

Author: Ward

I’m the creator and operator of this little corner of the internets, writing on all things related to art and more specifically my experiences trying to figure this whole thing out. I guess I’m trying to figure out life, too, but mostly I just post about art here.

Breath some fire into this post!

This site uses Akismet to reduce spam. Learn how your comment data is processed.