While Selenium IDE may seem a productive and efficient tool for writing test-cases, it lacks many essential features of a testing tool:
- Conditional statements
- Loops
- Logging
- Exception handling
- Reporting
- Test fixtures and data-driven tests
- Test dependencies
- Taking screenshots
- Selenium RC is the answer to a more powerful test-suite for your applications.
- It follows a client/server model allowing client libraries to execute tests on a browser controlled by the server.
- Selenium server is the program that drives the browser
- It embeds Selenium Core framework and injects it into the browser
- It communicates with the running test client and drives the browser
- Client tests sends commands that the server interpretes in order to drive the browser
- The server sends back results to the client
- Client and server communicates via HTTP GETs and POSTs so you can easily plug into
-
Server is configurable at startup via command-line options. use
java -jar selenium-server.jar -h
to see the list of options
- Client libraries provides the API to program tests and execute them on the server
- Each implementation provides access to all Selenium commands
Supported API implementation exists in:
- Java (also accessible via Groovy)
- .Net
- PHP
- Python
- Perl
- Ruby
- A JVM installed on the system
- A Ruby distribution with the rspec and selenium-client gems installed if
- you’re working
- The Selenium RC archive
In the folder of your choice, execute the following command:
git clone http://github.com/wolframarnold/selenium-test-app.git
Go to the
selenium-test-app
folder and run the following:-
cp ./vendor/plugins/active_scaffold/test/mock_app/config/database.yml ./config/
-
rake db:migrate
-
Now you should be able to lauch the application with the script
server
available in thescripts
folder:./scripts/server
-
The application should be available at
http://localhost:3000
- Unzip the Selenium RC archive somewhere on your system
-
Go into the
selenium-rc
, then theselenium-server
folder -
Open a terminal in this folder and enter the command
java -jar selenium-server.jar
- If there’s no error messages, your Selenium RC server should be running now.
- Create a new Java project in Eclipse or your Java IDE
- Add the selenium-java-client-driver.jar jar to the project’s classpath
- Add a new JUnit test-case to the project. When asked, select Junit 4
- You should now have an empty .java file
- Open the lab2 test-case on Selenium IDE
- On Selenium IDE, open the Options menu then Format… and click Java (Junit)
- Copy/paste the contents in the JUnit file on Eclipse
- Change the package name at your will
You may have to fix the imports
- Click on the following icon and choose the most appropriate option to correct the file
- You may also press Ctrl + Shift + O to let Eclipse do it automatically
- At this point you shouldn’t have any more errors and you are ready to run the test
- Selenium RC will open a couple of Firefox windows and run the test
- Open the lab2 test-case on Selenium IDE and export it as Ruby (rspec)
A little workaround is needed, open the exported file:
-
On line 47, where you should have:
/^Are you sure you want to delete <suggestion_name>[\s\S]$/ =~ page.get_confirmation.should be_true
-
Change it to:
page.get_confirmation.should match(/^Are you sure you want to delete <suggestion_name>[\s\S]$/)
-
On line 47, where you should have:
-
Run the test with
spec <filename>.rb
- Selenium RC should launch a couple of new browser windows and run the test
- Junit is the reference unit-testing framework for Java
- The framework allows you to test your applications using specific classes containing the logic performing actions on the tested classes and checking the results
- Eclipse provides support for Junit, so we’ll be using that
- JUnit 3 uses named methods to detect set-up and test methods
JUnit 3 cheat sheet:
import static org.junit.Assert.assertEquals; public class AdditionTest { //
DeepThought dt; public void setUp() { //
dt = new DeepThought(); dt.initialize(); } public void tearDown() { //
dt.closeQASession(); saveResult(); } public void testDeepThought() { //
int answer = dt.ask("What is the meaning of life, the universe and everything?"); assertEquals(42, answer); //
} }
The tests are embedded within a classic JavaBean The setUp()
method will be executed once, before any other methodtearDown()
method is executed after the last test methodName your tests methods following the testSomething()
pattern. They will be executed in the order of declarationJunit uses assert...
methods to provide verification of values.
![]() | Note |
---|---|
In our tests, we’ll use |
- RSpec is a Behaviour Driven Development framework for Ruby
- It provides a framework that tests your apps according to defined behaviors
- In Behavior Driven Development (BDD), you first define the behaviors of your app according to the client’s need, then your write the tests that validate these behaviors and then you start to develop your application.
- It is Agile-oriented
- Behaviors are defined in a spec file containing set-up methods as well as methods providing tests for a given behavior
-
You run tests with the
spec
command in a terminal RSpec cheat sheet:
require 'thing'
describe Thing do
before do
@thing = Thing.new end it "should find the Answer to the Ultimate Question of Life, the Universe, and Everything" do
@thing.answer.should == 42 end it "should enforce the Answer to the Ultimate Question of Life, the Universe, and Everything" do @thing.answer = 24 @thing.enforce @thing.answer.should be 42
end end
Load the tested file (you don’t need to specify the .rb extension) describe MyClass do
describe declares what is being tested
You can specify code to be run before ( before
) and after (after
). You can execute code before each example withbefore(:all)
Each example begins with it
followed by a string describing the behavior to be testedobject.should
andobject.should_not
are used to compare actual and expected valuesexamples:
-
o.should == <value>
ando.should be <value>
are equivalent -
o.should be_close <value>, <tolerance>
tests if a value is within a certain range -
o.should match <regexp>
tests if the value matches a regular expression -
o.should raise_error
tests if a method raises an error (you can specify the type of error as arguments) -
o.should have (5).things
tests if a collection contains 5 items exactly.have_at_least
andhave_at_most
are also available
-
- Since Selenium is based on JavaScript, you can use it in your tests
- It is an excellent way to extract information from the pages for later reuse
There are 2 methods available:
getEval(script)
: it takes the script as a string, executes it and return the value to which the script evaluates too. In ruby useget_eval
orjs_eval
Using this method, the
window
object refers to the Selenium context, which is different from the tested application’s JavaScript contextTo work around this, you need to get the application’s
window
object usingcurrentwindow = this.browserbot.getCurrentWindow()
* If you want to get an element, just useelement = this.browserbot.findElement("locator")
-
runScript(script)
: it actually adds a<script>
tag in the current page of the tested application, making it easier to debug
- Usually, fixtures designate the environment setup for the test-cases
- It is a very abstract notion and in practice it could be very different from a project to another depending on the project’s features
- In practice, fixtures are a set of tools allowing the test of an application under a pre-determined environment that produces previsible results
- The main motivation is to avoid errors due to changing environments and the side-effects that may occur
- In our case, Selenium doesn’t provide any support for fixtures so you have to do it by hand using your test framework’s fixtures capabilities
- RSpec and JUnit have support for fixtures through the set-up methods
- Test is brittle : change in the structure of the table displaying suggestions breaks the test
- Locators are complex
- We can’t do Fixtures
- You will first creates a suggestion
- Then you will find a way to delete that suggestion using only the id of the delete link
![]() | Tip |
---|---|
Observe the id of each table row and the corresponding delete link. You should be able to extract the numeric part of the id and use it to target the delete button. Use the following snippet to get the id: |
Java:
String script = "var suggestion_ids = new Array();" + "page = selenium.browserbot.getCurrentWindow().document;" + "table = page.getElementById('as_suggestions-content').childNodes[1];" + "var id = table.rows[2].id;" + "if(id && id != undefined) {" + " suggestion_ids.push(id.match(/[0-9]+/g));" + "}" + "suggestion_ids;"; selenium.getEval(script);
Ruby:
script = "var suggestion_ids = new Array();" + "page = selenium.browserbot.getCurrentWindow().document;" + "table = page.getElementById('as_suggestions-content').childNodes[1];" + "var id = table.rows[2].id;" + "if (id && id != undefined) {" + "suggestion_ids.push(id.match(/[0-9]+/g));" + "}" + "suggestion_ids;" suggestion_id = page.js_eval(script)
- Bonus: Make a loop that creates more suggestions and find a way to iterate over the table to delete them using javascript