A (still brief) experience on using Selenium to test a Rails + ajax app

This is a note to make a point on our (mine and my team’s) current use of Selenium to test the ajax behaviour in the Rails webapp we’re currently developing. Ajax replacing of part of the page is growing, and with it we have to face the classical question: “how do we test (I mean automatically :-) the ajax/javascript behaviours in our webapp?”.

This is how we are trying to manage this issue now, after some days of spiking on Selenium, Watir and BlueRidge (I hope to write more on Watir and BlueRidge in some future post, because these two tools are worth speaking).

Actually we are giving a try to the combination of Webrat + Selenium, since we already have a big test suite of integration test using Webrat, and have a good knowledge of the Webrat API.

We added the selenium-client gem to be able to drive Selenium through the Webrat API.
This is extracted from our test environment configuration file:

test.rb
...
config.gem 'selenium-client', :lib => 'selenium/client'
config.gem "webrat", :version => '>= 0.6.0'
...

Then, we defined a class from which all the selenium test cases will inherit.
This class basically is used to

  • disable the transactional fixtures in Rails, to allow the browser process where Selenium runs to access the data prepared in the tests
  • configure Webrat with the “selenium” mode
  • be the place to collect helper methods as “login” or “logout”, used in many tests.
selenium_integration_test.rb
class SeleniumIntegrationTest < ActionController::IntegrationTest
  self.use_transactional_fixtures = false

  setup :switch_webrat_to_selenium
  def switch_webrat_to_selenium
    Webrat.configure do |config|
      config.mode = :selenium
      config.application_environment = :test
    end

    selenium.set_speed(100)       # default is 0 ms
    selenium.set_timeout(10000)   # default is 30000 ms
  end

  teardown :delete_cookies
  def delete_cookies
    selenium.delete_all_visible_cookies
  end

protected
 ...
 [other helper methods here, like login, logout, and so on...]

 ...

We also added a rake task to be able to launch all the selenium tests

test.rake
namespace :test do
  ...
  ...

  desc "Run Selenium Test"
  Rake::TestTask.new(:selenium) do |t|
    t.libs << "test"
    t.test_files = FileList['test/selenium/*test.rb']
    t.verbose = true
  end
end

One thing we learned through several repeated mistakes is that the Webrat API is different when called in the “selenium” mode then the one we were used to when using Webrat in the classical “rails” mode.
For example, the “assert_have_selector” method for selenium only takes one argument, that is the CSS selector, while in the classical webrat mode, the same method takes another parameter to specify the expected content to match with (see this rdoc: http://gitrdoc.com/brynary/webrat/tree/master). So we had to define helper methods based on “assert_have_xpath” method using xpath to express the same intent of a method like assert_have_selector(css_selector, expected_content)

Here is our helper method

selenium_integration_test.rb
  ...
  def assert_has_id id, text_content
    assert_have_xpath "//*[@id='#{id}'][1][text()='#{text_content}']"
  end
  ...
Advertisements

Michael Feathers on testing private methods

Da un articolo di InfoQ, la posizione di M.Feathers sul testare i metodi privati:

Michael Feathers suggested last year in The Deep Synergy Between Testability and Good Design that TDD encourages good design and, conversely, code that is not testable should make us think twice:

When I write tests and I have the urge to test a private method, I take it as a hint. The hint tells me that my class is encapsulating so much that it has ceased to be “understandable” by tests through its public interface. I listen to the hint, and factor my design differently. Usually, I end up moving the private method (and possibly some methods around it) to a new class where it can be non-private and accessible to tests.

Condivido al 100%!

E interessante anche quello che dice dopo, nel post originale, riguardo alla relazione tra coupling, cohesion e testabilita’.

In the end, it all comes down to cohesion and coupling.  If classes are deeply coupled with their neighbors, it is hard to control them in a test or observe them independently.  If a class isn’t cohesive, it may have some logic which is not easily exercisable through its public interface.

It seems that reverse is true also.  Classes which are hard to instantiate and use in a test harness are more coupled than they could be, and classes with private methods that you feel the urge to test, invariably have some sort of cohesion problem: they have more than one responsibility.

Ascoltare i propri test, ovvero migliorare il codice partendo dagli smell dei propri test

Steve Freeman e Nat Pryce hanno iniziato una serie di interessanti post sul loro blog mockobjects sul tema dei Test Smells, ovvero su come ‘ascoltare’ i propri test per scoprire possibilita’ di miglioramento nel design del codice sotto test

In our experience, when we find that our tests are awkward to write, it’s usually because the design of our target code can be improved.

Una cosa su cui mi trovo d’accordo, piu’ che altro perche’ ho avuto la stessa esperienza in passato (e anche nel presente!)

Test Smells…

Il primo post della serie e’ Test Smell: I need to mock an object I can’t replace (without magic), dove si parte da un codice piuttosto ‘chiuso’, con dipendenze nascoste (magari usando dei Singleton), e passo passo lo si rifattorizza, aprendolo, prima introducendo un fake (o stub che dir si voglia) e poi passando ai mock, mostrando come il codice migliori, prima esplicitando le dipendenze e poi assegnando meglio le responsabilita’.

Se vi capita dategli un’occhiata!