Selenium Takes Rails Testing to Another Level June 27th, 2007
Rails has already make testing web easier. Rails project directory has specific test directory, named surprisingly ‘test’. You want to make unit testing for model? You write it in test/unit directory. Testing for controller? test/functional directory. It has fixtures support. It means you have specific database purpose for testing purpose. Your development and production database will not be touched. It has mocks support to simulate external resources. What could you expect? Testing Rails project is a nice experience.
But Selenium takes Rails testing experience to another level. With Selenium you have user testing beside model testing, controller testing. It means you have dummy user for your Rails testing purpose. What I mean with dummy user is you have user to test your Rails web project just like you test Rails web project with browser your self. This testing type is called black box testing (external view of testing). You input data to your application and see the output. Does the output is as you expected?
Selenium is not Rails specific project. It is actually development framework agnostic. It runs on your browser just like real users do. But writing raw testing for Selenium is not that fun. Selenium project has Rails specific support. It has Rails plugin, named Selenium on Rails. So I just talk about testing Rails application with Selenium here. To install it, just do this:
script/plugin install http://svn.openqa.org/svn/selenium-on-rails/selenium-on-rails
Selenium make testing Ajax part possible. So let’s make some scenario here. We have a page. Our page is a index page of admin controller (’/admin/index’). This page has link with value ‘Click this’. When we click this link, there will be text showed up somewhere in page. The text is ‘Selenium rocks’. How do we test this with Selenium on Rails? First, create a file in test/selenium directory. The extension should be .rsel.
# admin.rsel
open '/admin/index'
click 'link=Click this'
verify_text_present 'Selenium rocks'
That all it is. To run this test, you need to launch rails web server (mongrel or webrick) for test environment (to keep your development and test database save). To launch web server in test environment:
ruby script/server -e test
Open browser. Go to this url: http://your_rails_host:your_rails_host_port/selenium. You will have screen where you can see you testing steps, your test file, your web application, and buttons to launch test. Click the button and you will see invisible user testing your web step by step just like admin.rsel told it. The test result will be put below buttons.
That’s cool. We use a little bit more complicated scenario. We have ajax form with one text field. Assume the text field has id ‘bla_tf’. We type something in that text field, click commit button, then some text showed up somewhere in the page. The text is ‘Hello
# bla.rsel
open '/admin/bla'
type 'bla_tf', 'Akbar'
click 'commit'
wait_for_text_present 'Hello'
verify_text_present 'Hello Akbar'
Easy, huh?!!! click command can be used to click link and button. If it is a submit button, just use “click ‘commit’”. If it is a link, use “click ‘link=your link value’”. verify_text_present is intuitive so I don’t need to explain it, but what wait_for_text_present for? We use Ajax here, right? When you click commit button, Ajax form send the value to somewhere, wait for feedback, and put whatever feedback to the page. There is a delay. If we don’t use wait_for_text_present, the verify_text_present will fail immediately. We can use another command here, that is pause
Okay, are you still with me? We imagine what we type in that text field (that is ‘Akbar’ in the example) is inserted to database. How can we check whether the value has been successfully inserted into database or not. Selenium has no way to know that because it is designed for black box testing. We test by seeing the output. However you may use Selenium Remote Control (I have never used this) so you have direct access to Rails environment for checking database. But we can work around this problem. We use another controller for testing database. Clever, huh?!! I make special controller for this testing purpose. I make a filter method to make sure this controller is not run in production and development environment. Here is the controller.
class TestingController < ApplicationController
before_filter :must_be_in_testing_env
def check_name
name = MyName.find_by_content(params[:name])
name ? render :text => name.content : render :text => 'that name could not be found.'
end
protected
def must_be_in_testing_env
exit if RAILS_ENV != 'test'
end
end
Assume our text field value is inserted to MyName model. So this is our testing…
# whatever.rsel
open '/testing/check_name?name=Akbar'
verify_text_present 'that name could not be found.'
open '/admin/bla'
type 'bla_tf', 'Akbar'
click 'commit'
wait_for_text_present 'Hello'
# now we check the database if the value has been inserted or not
open '/testing/check_name?name=Akbar'
verify_text_present 'Akbar'
Pretty cool, huh?
Akbar