Showing posts with label test. Show all posts
Showing posts with label test. Show all posts

Sunday, December 18, 2011

Jbehave web and web drive

Objective

The purpose of this startup project is to get you going with jbehave web(3.4.3) and WebDrive. In this example we do a simple and basic task.
  • Load a website
  • Click on a link
  • And test if the redirected page is where we want to be

Required libraries

  • JBehaveWeb - Add all the jars from lib folder
  • Selenium - Add all the jar from lib folder and selenium-java-2.15.0.jar
  • JUnit 
A sample project is uploaded in github. It is simple enough to use as a startup project.
The implementation was done following this article.

Jbehave web and page object pattern

Objective

To explain  page object pattern and how to use it with jbehave web(3.4.3) and WebDrive.
A sample project is uploaded in github. It is simple enough to use as a startup project.
The implementation was done following this article. The basic is explained there, so in my post I will discuss about the page object pattern, which simplifies the web drive implementation.

Page object pattern

Each page has a one to one mapping with a java class
This might seem to be obvious to map all the pages with a java class. And the navigation from one page to another to map to a method of one object that returns the navigation page object. This approach increases readability in a great extant. Now look at a sample code(just to get an idea).
public class BasicWebSteps {

    private final Pages pages;

    public BasicWebSteps(Pages pages) {
        this.pages = pages;
    }

    @Given("user is on Home page")
    public void userIsOnHomePage(){        
        pages.homePage().open();        
    }

    @When("user clicks on Resume from menu")
    public void userClicksOnResumeLink(){        
        pages.resumePage().open();
    }

    @Then("Resume page is shown")
    public void runStoryPageIsShown(){
        pages.resumePage().assertShown();
    }

}
This increases the readability of the step definition. It encapsulates the logic of navigation, structure of page specific html,  page specific assertions for each pages in corresponding classes. This approach follows Single Responsibility Principle and makes a logical separation in the test project.
Jbehave help you to implement this pattern by providing WebDriverPage. So your parent class of each page might look like,
public abstract class AbstractPage extends WebDriverPage {
    public AbstractPage(WebDriverProvider driverProvider) {
        super(driverProvider);
    }
    ...
}
And a simple page can be like the following.
/*
 * Contains page specific
 *   HTML structure
 *   Assertions
 *   Navigation
 */
public class ResumePage extends AbstractPage {

    public ResumePage(WebDriverProvider driverProvider) {
        super(driverProvider);
    }
    
    public void open(){
        findElement(By.linkText("Resume")).click();
    }
    
    public void assertShown() {
        String output = findElement(By.cssSelector("#menu .selected a")).getText();
        assertTrue("Resume menu should be selected", output.contains("Resume"));
    }

}

Use annotation

Use jbehave annotation to simplify the code.

public class LoginPage extends AbstractPage {
 @FindBy(how = How.NAME, using = "username")
 private WebElement userNameElem;

 @FindBy(how = How.NAME, using = "password")
 private WebElement passwordElem;

 @FindBy(how = How.NAME, using = "role")
 private WebElement roleElem;

 @FindBy(how = How.NAME, using = "B3")
 private WebElement submitButton;

 public void loginAs(String profileName) {
  User user = User.getUser(profileName);
  userNameElem.sendKeys(user.getUserName());
  passwordElem.sendKeys(user.getPassword());
  roleElem.sendKeys(user.getRole());
  submitButton.submit();
 }

}

Sample project

The sample project can be found here.

References



Wednesday, December 14, 2011

Java Behavior Driven Development BDD

Objective

The purpose of this article is to get you going with jbehave, an elegant Java based BDD framework. This is a simple example of powerful jbehave. I missed a simple example of jbehave, so here is my effort.

Required libraries

The project is uploaded in github. It also has the dependency jars with it, so that you can start up soon.

References

Wednesday, July 8, 2009

Some of the useful way of using fixture better

1. Using new fixture facilities in rails 2.(example)

    Which will remove the relational fixtures for has_many :through and has_and_belongs_to_many relations.

    It will remove the ids and will give a better way of relating between tables.

2. Fixtures are read only:    Never modify any existing fixture, unless your database schema has changed.    Which also indicates that we should be very careful when are adding a new fixture.

3. Another way to identify if the fixture is well written is that they all should be meaningful.    And none of them should look similar.

   If a different fixture is needed for only 1 or 2 test, then update existing before doing the test.    For an example,

should 'assign responsible person to unassigned task' do
    task = tasks(:task_not_started)
    task.users.clear #clear the existing fixture(not creating a new one for that fixture) 

    assign_and_assert_responsible_person(task, users(:login_user))
end
This will reduce the number of fixture set and keep them clean.

4. Often we write test codes that involves a lot of fixture.    Some times when we get test fail, we run through the fixtures, trying to find out which went wrong.    But instead if we comment our code such a way that the fixture is understood from the test code,    then that would be even better. Like,

context 'in progress task' do
  setup do
    @task = tasks(:task_in_progress)
    # task -> time_estimates
    #         [ user: login_user, hours_spent: 2, hours_remaining: 8, entry_date: 1.days.ago ]
    #         [ user: developer , hours_spent: 4, hours_remaining: 3, entry_date: Date.today ]
  end

  should 'return hours spent upto' do
    assert_equal(2, @task.hours_spent_upto(1.days.ago))
    assert_equal(6, @task.hours_spent_upto(Date.today))
  end
end
5. Inherit fields, that are less likely to be different for each fixture
backlog_item: &common_backlog_fields
  project_id: scrumpad
  type: Story

bug:
  <<: *common_backlog_fields
  type: Bug
  title: Test Bug
  content: Bug content
  created_at: <%= 10.days.ago.to_s(:db) %>
  updated_at: <%= 3.days.ago.to_s(:db) %>

story:
  <<: *common_backlog_fields
  title: Sample story
  state: <%= WorkItem::COMPLETED %>
  created_at: <%= 10.days.ago.to_s(:db) %>
  updated_at: <%= 2.days.ago.to_s(:db) %>
Here we can define the common required fields in backlog_item and use that definition for other fixtures. The fields can be overwritten by redefining in the fixtures as we did overwritten type for bug.

Saturday, May 2, 2009

Testing model in rails

How we want our test environment

  1. Isolation of input fixtures, so that changing fixture of one test code will not impact others.
  2. Easily create input set and reuse existing.
  3. Readable test code.
  4. Runs very fast(Slower test codes are run less by developers).
  5. Write less to test.

Problems with built in fixture and test helper

  1. Fixture does not allow to isolate input set.
  2. No feature of reusability in fixtures causes developer to create unnecessary duplication in fixtures.
  3. Changes in table definition causes a lot of change in fixture set.
  4. Fixtures are hidden in different file. So it becomes difficult to trace a test code.
  5. Fixture is database driven. So even if you do not need a saved instance of an ActiveRecord object, you end up using one. The more the queries get executed, the slower the test code becomes.

Factory girl, one of the alternate of fixture seems to be the better solution then fixture. And shoulda makes the life easier for writing test codes.

Why factory?

  1. Isolated input set
  2. Different build method gives the flexibility to create saved and unsaved instances
  3. Can easily extend existing factory to create a new one
  4. Facility to override property and to stub methods to reduce database query
  5. Increase readability of test codes.

Why Shoulda?

  1. Context & Should blocks - Context and should block provides facilities to do BDD
  2. Assertions - Provides many common and useful assertions
  3. Macros - Generate many ActionController and ActiveRecord tests with helpful error messages

So let’s get some action. Here is a simple test done using factory and shoulda. We will write unit test for User model which looks like the following.

class User < ActiveRecord::Base
 has_many :posts, :order => 'created_at DESC'
 has_many :comments

 validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
 validates_uniqueness_of :email

 def display_name
   return "#{first_name} #{last_name}"
 end

 def latest_post
   return self.posts.first
 end
end

The Post model is,

class Post < ActiveRecord::Base
 belongs_to :user
 has_many :comments, :dependent => :destroy

 validates_presence_of :title
 validates_presence_of :body
end

And the user factory is,

Factory.sequence :email do |n|
 "email#{n}@test.com"
end

Factory.define :user do |u|
 u.first_name 'Ashraf'
 u.last_name  'Zaman'
 #allows you to create different users with different email using the same definition
 u.email { Factory.next(:email) }
end

Post factory is,

Factory.define :post do |p|
 p.title 'A sample post'
 p.body  'This is a sample post'
 p.created_at Time.now
 p.updated_at Time.now
end

Finally the user model test is,

require 'test_helper'

class UserTest < ActiveSupport::TestCase

 should_have_many :posts
 should_have_many :comments
 should_require_unique_attributes :email

 should_not_allow_values_for :email, "ab.cd", "1234@"
 should_allow_values_for :email, "ashrafuzzaman.g2@gmail.com"

 should 'display_name' do
   user = Factory.build(:user, :first_name => 'Ashraf', :last_name => 'Zaman')
   assert_equal('Ashraf Zaman', user.display_name)
 end

 context 'Default posts' do
   setup do
     @user = Factory.build(:user, :posts => [
         Factory.build(:post, :title => 'Second Post', :created_at => Time.now),
         Factory.build(:post, :title => 'First Post', :created_at => 2.minutes.ago)
       ])
   end

   should 'return latest post' do
     assert_equal('Second Post', @user.latest_post.title)
   end
 end

end

You can download the demo from here

How factory helped

To test the display_name I do not need a saved instance, So I used Factory.build to build the model object with out saving it in the database.

Note: With Factory.build you can create an unsaved model instance from the factory prototype. It is very useful for testing model logic.

Some attributes of user prototype are intentionally redefined to increase the readability of the test code. Now you can easily read the test code as you can see the input set right in front of you. Thus you can effortlessly create different input set from one basic prototype.

The interesting part of this section is the test of latest_post of user model. Here as you can see the association method ‘posts’ is overridden with expected post list. Now you can mock this this methods as this is provided by the framework itself. So no need to test it. But by mocking this you actually increased the readability of the test code and avoided database call.

How shoulda helped

The Shoulda gem makes it easy to write elegant, understandable, and maintainable Ruby tests. Shoulda consists of test macros, assertions, and helpers added on to the Test::Unit framework.

With shoulda we defined a context 'Default posts' and initialized it. We can test codes related to posts with in the context. As the context is setup with the minimum and sufficient information of input set needed for the context, the test code becomes very simple and easy to read and maintain.

Resources

http://thoughtbot.com/projects/factory_girl

http://thoughtbot.com/projects/shoulda

Monday, April 27, 2009

Using webrat for integration testing

What is webrat

Webrat lets you quickly write expressive and robust acceptance tests for a rails application.

How Webrat is different from default rails integration test

1. Rails default integration testing is nothing more than a series of functional tests. But in webrat you can actually do actions in pages. Here is a scenario for login.

visit('/')
fill_in('email', :with => user.email)
fill_in('password', :with => '1234')
click_button('login')

2. With webrat you can test user experience by filling in the text boxes, clicking the buttons etc.

3. Use webrat API for Browser Simulator and real Selenium tests using Webrat::Selenium when necessary (eg. for testing AJAX interactions).

4. Supports popular test frameworks: RSpec, Cucumber, Test::Unit and Shoulda

Installing webrat

gem install nokogiri
gem install webrat

In test_helper.rb add,

require "webrat"

Webrat.configure do |config|
 config.mode = :rails
end

For more information please visit http://github.com/brynary/webrat/tree/master

Some Tips

You can check something like, if your desired dropdown select option is currently selected or not using assert_select.

Let me show you the expected html to test

<select name="user[user_type_id]" id="user_user_type_id">
 <option selected="selected" value="1">Shipper</option>
 <option value="2">Transporter</option>
</select>

Here we want to test of Shipper is selected or not.

So the test code can be

test 'signup form with shipper' do
 visit('/')
 click_link('Signup as Shipper')
 assert_selected_option('user_user_type_id', 'Shipper')
end

def assert_selected_option(select_id, selected_text)
 assert_select("##{select_id} option[selected=selected]", selected_text)
end

This is how you can test contents of html.

Resources

http://github.com/brynary/webrat/tree/master

http://www.slideshare.net/brynary/webrat-rails-acceptance-testing-evolved

http://cheat.errtheblog.com/s/webrat/

Monday, April 13, 2009

DateTime with zone support in rails fixture

To get time with zone support we usually call, Time.now.utc

But if we use Time.now.utc in fixture like,

fixture1:
deadline: <%= Time.now.utc %>

It gives an error:

ActiveRecord::StatementInvalid: Mysql::Error: Incorrect datetime value: 'Sun Apr 12 11:40:05 UTC 2009' for column 'deadline' at row 1: INSERT INTO job_assignments (job_id, updated_at, id, deadline, transporter_fee, transporter_id, created_at, state) VALUES (245383586, '2009-04-12 09:40:07', 809788707, 'Sun Apr 12 11:40:05 UTC 2009', 75, 468814034, '2009-04-12 09:40:07', 'assigned')

Because fixtures calls a default to_s function for each fields to create the insert script. Fixtures does not save records through Models. Time.now.utc.to_s generates a string which is not in the format to save date time in mysql. To generate such format we need to call Time.now.utc.to_s(:db). So the fixture turned out like,

fixture1:
deadline: <%= Time.now.utc.to_s(:db) %>

Sunday, January 11, 2009

Test rails with Mocha

Rails is a framework that came up with facilities for testing using fixtures. Testing using  fixture is a nice feature to have for a small project. But as the project grows some problems might be seen. Like,

  1. Difficult to manage fixture
  2. Takes long time to run the test

Difficult to manage fixture:

As it becomes hard to manage fixtures, people tends to add and do not intend to reuse existing, as that might break current test codes.

So the number of the entry in fixtures increase day by day. Eventually it becomes unmanageable.

Takes long time to run the test:

As fixture driven testing takes a lot time to run the test. People don't feel comfortable to run test for a large project. Even running one test file sometime takes 2/3 minutes. We use Continuous Integration(CI) to run test for the whole project in different server, while we do our regular tasks. But even that is not working out for us right now. Because, It takes about 30 minutes to test the whole project. CI looks up in repository and check for changes and if found any, it starts to build and run test. So If any code is checked in with in with in 30 minutes while the build is not completed, then that build goes into queue. And eventually we get the email notification from CI after 1/2 hours. Which is not satisfying the purpose of CI.

Solution:

I read about Mocha and really got interested. It is a solution to fixtures. You can use mock object to replace fixtures. At first I was confused about how should I mock my model objects. As it contains the business logic as well as the logic to save in database. Mocha gives you a solution as it gives facility to overwrite methods for an object without writing a real class. So you can mock save or find method of ActiveRecord and replace it with mock method with out creating a class. You can even mock a private method. Here is an example.