TestWise IDE

Next Generation Functional Testing Tool

5 Refactoring

The article Refactoring Automated Functional Test Scripts with TestWise introduces the ‘page objects’ and covers the refactoring step by step. It is highly recommended to read it first.

Refactoring has been widely used in programming, and its practices are regarded as one of most important advancements in software development in recent decades. Now with TestWise, you can do it with ease. For users with programming experiences, some of practices may be familiar; For ones without, don’t worry, it is not that hard anyway in TestWise.

5.1 Extract Function

Motive There are test steps that are performing common operations such as Log In, and User Sign Up. You want a simple way to reuse them.
Outcome The selected test steps are extracted to a function, and quite commonly moved to a helper file, where they can be shared by all test cases.
Benefits More readable scripts; Less duplication; Test scripts reuse
1. Identify the test steps

For example, the test steps below logs a user in.

test "[124] Sample test case name" do
  # steps before ...
  enter_text('username', 'john')
  enter_text('password', 'foobar')
  click_button('Login')
  # steps after ...
end
2. Select the test steps

Select those test steps.

If there is only one test step, then you may skip this step. TestWise will take the current line as ‘selected test step’.

3. Invoke the refactoring

There are two ways to invoke the ‘Extract Function’ refactoring. Firstly via ‘Refactor’ Menu,

Or using the shortcut key (Ctrl+Alt+M).

def login
  enter_text('username', 'john')
  enter_text('password', 'foobar')
  click_button('Login')
end

test "[124] Sample test case name" do
  # steps before ...
  login
  # steps after ...
end
4. Move the function to a helper

Run the test case, make sure it is running as expected. After that, it is generally a good idea to move the new function to a helper (If you follows TestWise convention, a test_helper.rb shall already be created), so that every test case can just use it.

# Now in test_helpe.rb
def login
  enter_text('username', 'john')
  enter_text('password', 'foobar')
  click_button('Login')
end

5.2 Extract Page

Motive You have recorded or entered some test steps, and noticed duplications. As time goes on there will be even more duplications, which leads to hard-to-maintain test scripts.
Outcome You have recorded or entered some test steps, some o
Benefits More readable code by expressing operations in DSL; Test Scripts Reuse; More immune to application changes; Enable other convenient operations like auto-complete in TestWise.
1. Identify the test steps on a web page

It is quite easy, you probably have been saying it out all the time. Quite often, we hear people saying like this “On homepage, click sign up link to get to the signup page, then enter preferred login …”.

For this example, we will try extract operations to SignUpPage. For the sample script below, From line 3 to line 8 are operations on the sign up web page.

test "[124] signup a new user" do
  logout # a function
  click_link 'Signup'
  enter_text("login", "John")
  enter_text("password", "foo")
  enter_text("passwordConfirmation", "foo")
  select_option("country", "Australia")
  click_button("Submit")
  # steps after ...
end
2. Move the caret to first operation on wanted page

In this case, it is enter_text(“login”, “John”).

3. Invoke ‘Extract Page’ refactoring

Either from the menu

Or shortcut key (Ctrl+Alt+G)

4. Enter the page and operation names.

It is like filling “on _____ page do _____”. For our example, we fill ‘SignUpPage’ and ‘enter_login’. Please note the convention here, Camel Case for page names, and lower case (joined with _) as operation (or function) names.

The test script is now changed to

 test "[124] signup a new user" do
    logout # a function
    click_link 'Signup'
    sign_up_page = expect_page SignUpPage
    sign_up_page.enter_login
    enter_text("password", "foo")
    # more ...
 end

And a new file sign_up_page.rb is created under pages folder with the following content.

class SignUpPage < RWebUnit::AbstractWebPage

  def initialize(browser)
    super(browser, "")
  end

  def enter_login
    enter_text("login", "John")
  end
end

Rerun the test case.

5. Continue refactorings to remaining operations

Complete refactored test case:

  test "[124] signup a new user" do
    logout # a function
    click_link 'Signup'
    sign_up_page = expect_page SignUpPage
    sign_up_page.enter_login('john')
    sign_up_page.enter_password('foo')
    sign_up_page.select_country('Australia')
    sign_up_page.submit
    # steps after ...
  end

In SignUpPage (file: sign_up_page.rb)

class SignUpPage < RWebUnit::AbstractWebPage

  def initialize(browser)
    super(browser, "")
  end

  def enter_password(pwd)
    enter_text("password", pwd)
    enter_text("passwordConfirmation", pwd)
  end
  def select_country(country)
    select_option("country", country)
  end
  def submit
    click_button("Submit")
  end
  def enter_login(login)
    enter_text("login", login)
  end
end

Careful readers might notice the above is a little different from results from refactoring. Yes I made some changes by hand to introducing parameters. This can be done by another refactoring ‘Extract parameter’, which is not implemented yet in TestWise v1.

In test case:

   select_country

In sign_up_page.rb

   
  def select_country
    select_option("country", 'Austrlia')
  end

By parameterizing the function ‘select_country’, we can user “select_country ‘USA’”, “select_country(”Japan") in our test cases without the need to changing the function.

6. Reuse the page object.

Refactoring is done. Your test case is more readable (feel free to use your own domain terms there), and more importantly, if changes made to that web page, you know there is only one place you need to change.

There is more. TestWise ‘understands’ the page objects. For example, in a new test case involves the signup page, after typing ‘sign_up_page.’, the defined operations on that page will populate for selection.

5.3 Copy

Motive You want to create a similar page class like an existing one
Outcome A new page class created with same content, but with correct class name.
Benefits Less typing
1. Open an existing page file
2. Invoke the refactoring

Eiether from the ‘Refactor’ menu or simply pressing Shift+F5.

3. Enter new file’s name

A new page (profile_page.rb) is created.

5.4 Rename

Motive The terminology or application changes make names used in existing test cases are not correct or leads to misunderstanding. Or simply find a better name.
Outcome The terms used in test cases are up to date with your domain language
Benefits More readable test case; No error-prone ‘search and replace’ in whole projects

This refactoring can also be further classified into the following sub ones.

  • Rename Page Class
  • Rename Function Name
  • Rename Local Variable
  • Rename Instance Variable
  • Rename Global Variable
1. Identify a function name, class name, variable name

Just move the caret to the name you wish to change.

2. Invoke the refactoring

Either from the ‘Refactor’ menu or simply pressing Shift+F6. TestWise will analyse the script to choose appropriate subrefactoring.

3. Enter the new desired name

Depends on the subrefactoring, changes will be made accordingly.

SubRefactoring What Changed
Rename Page Class Page Class declaration and all appearances of the page class name
Rename Function Function declaration and all references to that function
Rename Local Variable All appearance of variable in that scope
Rename Instance Variable   All appearances of the instance variable (like @username) in current file.
Rename Global Variable All appearances of the global variable (like $SERVER_NAME) in all project files.