Agile Outsourcing, from Idea to tested Software

Archive for the ‘Testing’ Category

Rails 3: Functional controller testing when using devise and declarative authorization gems Christian S. 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 Christian S. 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)

Acceptance Test Driven Development (ATDD) Christian S. 20 Sep 10

1 Comment »

Acceptance test driven development is an agile software development method that uses the Acceptance tests to establish when a requirement meets the client’s expectation. It is an advanced practice of the Test Driven Development method.


Acceptance tests or Customer tests are written by the client together with the developers for every requirement that is part of the specification. Whereas a requirement describes specific behaviour the client wants in the finished software, the Acceptance tests make sure that the requirement was implemented in its completeness and according to the client’s input.
As an example we can use the tried and tested password requirement:

Requirement “When a user is creating an account, he/she is required to choose an outlandishly secure password”
Acceptance Test1 Test that the password contains at least 8 characters with at least one upper case letter, a number and a symbol”
Acceptance Test2 Test that the password does not contain a word from the english dictionary”
Acceptance Test3 Test that the user receives different error messages when the password is too short, contains no upper case letter, no number or no symbol. “
In this case the Acceptance tests define now what an “outlandishly secure password” is and increase the shared understanding for this requirement. And after the tenth iteration I can make sure that these Acceptance tests still pass so I have regression testing built right in.


The many benefits of ATDD

  • Acceptance Tests increase the shared understanding of a requirement because they are a product of direct interaction between the client and the developers.
  • Clarifies requirements and keeps the developers focused on what the client really wants.
  • Drives out ambiguity if certain behaviour is ultimately a bug (behaviour violates either requirement or tests or both) or a change request (behaviour is acceptable within the scope of requirement and acceptance tests but ultimately undesirable).
  • Software delivery is now dependent on all Acceptance tests passing and with that defines when a project is done.
  • Percentage of passed acceptance tests/all acceptance tests acts as a project progress indicator.
  • Free regression tests for the future iterations (especially if automated).


Some ATDD drawbacks

  • Client interaction is needed which can prove difficult due to time constraints
  • More work for the developer if tests are automated.
  • Project progress might be slower due to additional effort.


Automating ATDD
There are many tools and frameworks for acceptance test automation, even some that can be used for User Interface testing. Many of them are free and open source, so the framework can be adapted to suit the project. Automating acceptance tests is highly desirable because regression testing is a hugely important step for iterative agile development methods. The immediate drawback is that this also means the developer has even more work to do because test automation is a development task in itself.


Are Unit tests not needed anymore?
Acceptance tests are no replacement for Unit tests. Unit tests must still be written by the developers to make sure that the code they are writing is performing as it should. Unit tests are written to test individual units of source code, whereas Acceptance tests are written to test several units of source code connected by some type of workflow defined by the client.


ATDD and outsourcing
ATDD is very much suited for outsourcing because its previously listed advantages address many of the issues encountered in outsourced software development. But it is important to notice that it will only work if the project is using an agile development method and can’t be shoehorned into a waterfall based development scenario of design first, development second, testing third. ATDD needs commitment from both the project owner and also the agile supplier because the real emphasis is not necessarily on the testing itself but on the increased shared understanding that is a product of the increased contact between the two parties. Including ATDD will also most likely increase the cost of the project at the start as more time is needed by the developers to write the additional tests. The real gain comes over time as the functionality of the delivered software should with every iteration be closer to what the client envisaged in the first place and therefore should reduce the need to add or refine functionality. The Acceptance tests also act as a baseline that can be consulted if a dispute about the scope should arise.


Acceptance Test Driven Development and the cost of (not) testing Christian S. 20 Jul 09

0 Comments »

All requirements that were created in the last step have one issue, they describe in (hopefully) simple words the business requirement that was created using the insight of end user and the developer. But this is a description of functionality as it should happen in the best case. So there will be a good bit of ambiguity in a requirement.


This is where acceptance tests are coming in. At the start they are simply notes about what should be tested for every requirement. Acceptance tests are later often used as the criteria to verify whether a requirement was fully implemented and this makes a lot of sense. Because the initial tests are described again in plain english and outside of a technical framework, the end users should define the bulk of them. Also new tests should be added over time to cover all eventualities.


Acceptance tests should be defined before a line of code is written as they provide a lot of information for the developer that could be interpreted differently due to requirement ambiguity. They also create boundaries for the requirement and limit the amount of work that is needed for a given requirement. Tests should be integrated into a test automation framework so they can be reused for every iteration and with that become automated regression tests that make sure any new iteration did not break what was developed in an earlier iteration. There are many frameworks out there like Fit, Fitnesse and Selenium that can help with this automation.


But besides Acceptance Tests, it is important to request that the developers also write lower level unit tests during development. When combining both lower level unit tests and higher level acceptance tests quite a good amount of test coverage is achievable.


Unfortunately testing comes with a steep price tag. Most outsource companies slapped on between 25-50% for extended repetitive manual testing (poor testers). It has to be said that requesting proper automated unit testing and acceptance testing is a development step in itself because tests have to be written in much he same way as the rest of the software. But as a project goes over several iterations, regression tests will help finding issues early rather then at the last test run. In our opinion paying for testing should mean that the tests are automated and can be reused in later iterations or even releases. Manual testing is error prone and one of the least motivating pieces of work and should be best avoided if possible.