h2. 5 Refactoring
* 5.1
Extract Function
* 5.2
Extract Page
* 5.3
Copy
* 5.4
Rename
The article "Refactoring Automated Functional Test Scripts with TestWise":http://www.infoq.com/articles/refactoring-test-scripts 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.
h4. 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 |
h5. 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
h5. 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'.
h5. 3. Invoke the refactoring
There are two ways to invoke the 'Extract Function' refactoring. Firstly via 'Refactor' Menu,
!/images/manual/RefactorMenu-ExtractFunction.png!
Or using the shortcut key (Ctrl+Alt+M).
!/images/manual/Refactor-ExtractFunction.png!
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
h5. 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
h4. 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. |
h5. 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
h5. 2. Move the caret to first operation on wanted page
In this case, it is
enter_text("login", "John").
h5. 3. Invoke 'Extract Page' refactoring
Either from the menu
!/images/manual/RefactorMenu-ExtractPage.png!
Or shortcut key (Ctrl+Alt+G)
h5. 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.
!/images/manual/Refactoring-ExtractPage.png!
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.
h5. 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.
h5. 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.
!/images/manual/Refactoring-PageFunctionAutoComplete.png!
h4. 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 |
h5. 1. Open an existing page file
h5. 2. Invoke the refactoring
Eiether from the 'Refactor' menu or simply pressing Shift+F5.
!/images/manual/Refactoring-CopyFile.png!
h5. 3. Enter new file's name
A new page (profile_page.rb) is created.
h4. 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
h5. 1. Identify a function name, class name, variable name
Just move the caret to the name you wish to change.
h5. 2. Invoke the refactoring
Either from the 'Refactor' menu or simply pressing Shift+F6. TestWise will analyse the script to choose appropriate subrefactoring.
!/images/manual/Refactoring-RenameFunction.png!
h5. 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. |