Agile Outsourcing, from Idea to tested Software

Archive for the ‘Technology’ Category

Rails 3: Functional controller testing when using devise and declarative authorization gems 28 Jun 11

0 Comments »

One has to give it to the developers of devise and declarative authorization, they have really created extremely useful gems. As we are using these gems extensively in our own product and also for client products and projects, we also need to test them. Now both gems offer very helpful test helpers which need just a little bit of help to work together. The issue arises if a controller takes advantage of both gems where we found ourselves faced with disappearing session values after signing in with devise. But after digging a little bit in the declarative authorization source code, we found how to make the two gems work together for testing. The same post can also be found on Github


Below code example seems to work for Rails 3.0.6, devise 1.1.5, declarative authorization 0.5.3.


The sign_in test helper from devise adds the key/value pair “warden.user.user.key” => ["User",id] to the session and one has to explicitly add the session to the declarative_authorization get_with helper. The *_with methods call the request_with method which defaults the session argument to an empty hash unless one explicitly provides the session.


And without the above mentioned key/value pair in the session when calling get_with, one will not get past devise’s authenticate_user! before filter.


The following test in the users_controller_test.rb works when trying to access the users_controller show action which is included in the filter_resource_access and has an appropriate rule listed in the authorization rules:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#config/authorization_rules.rb
role :authenticated do
    has_permission_on :users, :to => [:show] do
      if_attribute :id => is { user.id}
    end
end

#app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_filter :authenticate_user!
  filter_resource_access

  def show    #@user is already loaded through filter_resource_access method of the declarative_authorization gem
    respond_to do |format|
      format.html  { render :action => :show}
    end
  end
end

# test/test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'declarative_authorization/maintenance'
require 'rails/test_help'

class ActiveSupport::TestCase
  include Authorization::TestHelper
  fixtures :all
end

# test/functional/user_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionController::TestCase
  include Devise::TestHelpers
  setup do
    @user = users(:authenticated)  #this user must obviously have symbol :authenticated as an element of the role_symbols array
   end

  test "should get to show action if current user is equal to the called resource" do
    sign_in @user
    get_with @user, :show,{:id=> @user.id}, session #this is where the session from sign_in is added to get_with
    assert_response :success
  end
end

User Acceptance Testing with Selenium IDE: How to handle Javascript Alerts, Ajax Popups and Drag and Drop 08 Oct 10

2 Comments »

We have been using Selenium successfully as an automated tool for Acceptance Testing all releases from our outsourcing provider. Even though we have written many of the testcases in ruby, using the IDE to create testcases in Selenese has been enough in many cases. Every release we receive is tested using the old test suites to make sure the new functionality does not break existing one, this step is also called regression testing. Selenium works great for applications with an already advanced user interface that will not change significantly over time any more. Otherwise a lot of time will be spent debugging the testcases themselves. One way around this is to use a fixed id for the elements used in testing, but that might not always be possible.


Tip:If you have access to the database, create a database dump after running a test suite. If you have to do manual tests in between test suites then create a db dump before AND after. This will make your life a lot easier if your tests are dependent on previous tests which they probably will be. Now if one of the tests in a test suite fails, you just reload the database and start the test suite again.


We used Selenium and found it to work very well with our AJAX enabled website, but it took some time to get the head around the topics described below. The following examples worked in Firefox 3.6.10 and Selenium IDE 1.0.7.


The documentation was pretty useful and the API covered most other topics not found in the documentation.
Selenium IDE documentation
Selenium Selenese Commands
Selenium 1.0 API


AJAX/Javascript in general

When you are using AJAX/Javascript, the web page will most likely not actually reload. Therefore Selenium will not know if and when an element in the page is available and the verify* or assert* commands will often fail. This is where the waitFor* commands come in. For all these commands Selenium will repeatedly check whether a certain event came to pass until a set time out is reached. By default the time out is set to 30 seconds but can be manually adjusted using (surprise surprise)


setTimout( timeout in milliseconds) –> setTimeout(5000) –> sets timeout to 5s
Once set, the timeout will stay at 5s.


AJAX or “in browser” popup

Many web applications now use what we call an “in browser” popup, this is NOT a smaller new browser window and NOT a Javascript alert. Most of the time it is a hidden DIV element at a relative or fixed position that is shown and hidden using javascript and might be populated with data from the server using AJAX. It is very often used for data entry and therefore will have to be tested with Selenium.


  • Use waitForVisible if the element’s CSS attributes include “visibility:hidden” or “display:none”.
  • Use waitforElementPresent if the element did not exist before. This will not work for the above situation because the element itself is present, even though it is not visible.


Tip:use waitFor commands in sequence if you are waiting for an element in a container. For example you have to test an AJAX action that populates a hidden DIV with a page from the server that contains input fields and then makes the DIV visible. As part of the test you most likely will have to populate these inputs fields. In that case use waitForVisible for the DIV container first and then use the waitForElementPresent for the first input field. Even though Selenium verified that the DIV is now visible, it still is not a guarantee that the browser already loaded the form with the inputs fields from the server. So the test will most likely behave slightly erratic, sometimes it passes and sometimes it will fail. Using a sequence of waitFor commands will make sure that the elements are available at the time of the test step.


Javascript alert boxes/confirmations

Javascript alerts are a bit of a problem for Selenium and there are even situations where the box has to be clicked manually. (From the documentaiton: Selenium does NOT support JavaScript confirmations that are generated in a page’s onload() event handler. In this case a visible dialog WILL be generated and Selenium will hang until you manually click OK.)


But most of the time it is possible to deal with this pesky little alert boxes. When recoding the test using Selenium IDE the alert boxes appear as normal and the IDE will happily record a “assertConfirmation” command, but when running the test, no alert box shows up and the test often fails. It is important to know that alert boxes are NOT shown when running the test as noted in the Selenium documentation. And replacing assertConfirmation with waitForConfirmation most of the time allows the test to pass.


All commands use a positive confirm, so if you want to test the negative confirmation use chooseCancelOnNextConfirmation BEFORE the action that results in the alert box.


Drag & Drop

Even complicated actions like drag and drop can be implemented using the Selenium IDE only. In our case we had the following setup to test.

  • Two DIVs side by side with ids “account” and “team”, the “account” DIV containing a table of account users not in a project team and the “team” DIV containing the table of the project team users.
  • The users were distinguished using their unique email address and the table position for a specific user is dynamic in both DIVs.
  • Dragging a user from the “account” into the “team” DIV also opened an “in browser” popup to choose the project roles for that user.
  • Once the user was moved over in the “team” DIV, we needed to check that the email address was in the table of the “team” DIV.


Command Target Value Comment
mouseDown //div[@id='account']/table/tbody/tr[1] Click the left mouse button over the first user in the table (uses an Xpath locator)
storeText //div[@id='account']/table/tbody/tr[1]/td[2] email Store the email address of the user in the variable “email”
mouseMoveAt team Move the mouse over the the “team” DIV (using the id as locator)
mouseUp team Now release the left mouse button over the “team” DIV
waitForVisible popup_div Wait for the “in browser” popup “popup_div” to become visible
click //input[@id='roles_' and @name='roles[]‘ and @value=’4′] Tick a checkbox for the user to get that role in the team
click project_user_submit Press the submit button of the form for the roles. This also closes the “in-browser” popup
echo ${email} Just for debugging, show the value for the variable “email”
waitForText //div[@id='team']//a[text()='${email}'] ${email} Now wait for the user with the unique text value “email” to appear in the “team” DIV


Tip:Don’t move the mouse when running a test that contains mouse movement commands, otherwise your mouse movements will interfere with Selenium and the test will very likely fail.

Tip:Use the echo command to check your variables in the log (works if set to info)

Ruby on Rails: a design decision 30 Nov 09

0 Comments »

We had heard about Ruby on Rails and how efficiently one can create web applications with a handful of good developers and we were intrigued to find out more. Due to budgetary constraints we would not use a platform that we would have to pay for to run our service and we all had now used open source components for years. After playing around with Ruby on Rails for a while we were convinced that Ruby on Rails really is a great language/framework combination. We also felt very quickly at home with the Ruby language itself and found a huge amount of plugins/gems and a vibrant community. Also there are many great online services out there already running on Ruby on Rails on Linux for a while, so the majority of issues running an online service were already ironed out. But what really convinced us was that it implements the tried and tested model view controller pattern in an easy and straightforward way. We were sold.


Once again we are not advocating that Ruby on Rails is the only right choice but at the time we felt that it was the optimal choice given our background. Ruby on Rails in the end is just a tool set and there are many great tool sets out there that have their place in the right context. At the time of the post we are still very enthusiastic about our choice.