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.

Create Icons Easily

Want to quickly create icons quickly that all follow a similar size, coloring, and text?  Then check out http://www.rss-icon.com/icon.php

We used this on http://kotoba.wardosworld.com to quickly add customized icons for our blog and twitter.

Basically, you can enter in the text, size of the icon, colors of background and text to generate an image.  The image, when downloaded will typically include the suffix, .php.html.  Just change this to .gif and you are done!

For those wanting a quick translation of the UI, use the below cheat sheet.

文字タイプ: Font

文字サイズ: Font Size

アイコンの幅: Icon Width (in pixels)

アイコンの高さ: Icon Height (in pixels)

中心のボーダーの位置: Position of middle border (in pixels)

外側のボーダーの太さ: Outside border width (in pixels)

内側のボーダーの太さ: Inside border width (in pixels)

左ボックス-内容: Left box’s content

左ボックス-文字色: Left box’s font color

左ボックス-背景色: Left box’s background color

左ボックス-間隔: Left box’s padding (in pixels)

右ボックス-内容: Right box’s content

右ボックス-文字色: Right box’s font color

右ボックス-背景色: Right box’s background color

右ボックス-間隔: Right box’s padding (in pixels)

Once you filled things in click on アイコンを作成!

The image that appears can be saved to your computer.  Remember, you will rename so that the suffix is .gif.

Kotoba is Fav’conified

 

Kotoba FavIcon
Kotoba's new favicon.

Sometimes it is the little things that can make you smile.  Case is point is Kotoba‘s new favicon.  

I wanted something that was clean and easily recognizable in the toolbar.  While options included something abstract, I felt that a monogram might best represent the intent of the site.  While “K” might be arguably more universal, I ultimately decided that the 「言」という文字 is both identifiable to many using the site and abstract enough to act as a “logo”.

In order to create the image, I went through the process of  getting various Japanese-supporting applications installed just to create a very simple image.  This process culminated in the installation of OpenOffice.org’s OpenOffice and  Gimp.   

There is a wealth of information about installing Japanese versions of these pieces of software:

In the end, installing the latest versions of both OpenOffice and Gimp is sufficient to get out-of-the-box compatibility with Japanese display and input.  While OpenOffice supports Japanese input directly into the application, the same cannot be said for Gimp.   Nevertheless, it is relatively painless to use OpenOffice to create images with Japanese text that can then be imported directly into Gimp.  

Once we had a means of creating an image, the final step is to get it into a format that is universally used by web browsers.  I lucked out when I found the very  wonderful website, http://www.favicon.jp/, which will take any image and create a version in .ico format.  Once this file is generated, it is straight-forward to added to your site you can point to it in your HEAD tag.

And that is how we get something small but that gives us a large, warm fuzzy in our tummy.  😀

Phase II Complete

It took me a bit of wrangling, but I believe Phase II of the project is now complete!  It too me three different UI approaches to managing vocabulary lists before I finally settle on a set of functionality that meets my design goals.  It is now possible to add vocabulary lists that are only editable by you.  While other people can see this lists and use them as-is for their own learning, they cannot edit them.  Eventually, I will add the ability to share lists between people but that is for a future day.  Once a vocabulary list is created you can either add words from the list itself, or by browsing words.  When editing words, you will only see your lists that you can attach a word.   Hopefully the current approach is one that people find intuitive and easy to use.

Multi-byte Strikes Again

Multi-byte support, while by-and-large a now a well-supported stable of modern programming languages, is still something that trip up a person from time to time.  In particular, while UTF-8 is the de facto standard for encoding it does pose an issue when you get down to the character level.

I ran into this today while trying to shrink a potentially large bit of text to a manageable “chunk” of characters.  Ruby, it appears, separates a string into 8-bit characters.   When grabbing a substr from a string with mixed Japanese and English you end up with the dreaded 文字化け (mo-ji-ba-ke); something now only whispered in darkened corners from veterans reliving the horror days before unicode.

Well, the short of the long is a nice bit of hackery provided by at 山下英孝.  Basically, the trick involves a slice after grabbing the characters directly from the string.

However.  While this is a fun hack, it is hack.  The better way to handle this is to use chars instance method on the String class.  This ensures that a character is a logical character (e.g. ‘a’ or ‘あ’) and not the physical char returned directly by the array.

In summary, you want to use:

multi_byte_string = "私のマルチバイト文です。My multi-byte sentence."
# this is a hack of the physical characters
# you can, of course, use this; but, you should not
multi_btye_string[0,5].slice(/\A.{0,}/m)
# Instead, this is a much better approach which uses 
# all the UTF-8 goodiness to get logical characters from the string
mutli_byte_string.chars[0,5]