Appeared an unexpected pre-requirement of our client, our client asked that the tests they are run on multiple browsers, Firefox, Chrome, Internet Explorer by default, of dynamic form and simple. For this lets go now create another class, class with the browsers name, with function to set browser specific chosen and return the browser instantiated.
Create directory classes and create browsers.py:
Our class for example:
__author__ = 'Reinaldo Mateus Rossetti Junior'
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
class browsers(object):
def setBrowser(self,browser):
if browser == "FIREFOX":
#Running Standalone Selenium Server for use with RemoteDrivers, port 4441
WEB_DRIVER = webdriver.Remote(command_executor='http://127.0.0.1:4441/wd/hub',
desired_capabilities=DesiredCapabilities.FIREFOX)
return WEB_DRIVER
elif browser == "CHROME":
WEB_DRIVER = webdriver.Remote(command_executor='http://127.0.0.1:4441/wd/hub',
desired_capabilities=DesiredCapabilities.CHROME)
return WEB_DRIVER
elif browser == "IE":
WEB_DRIVER = webdriver.Remote(command_executor='http://127.0.0.1:4441/wd/hub',
desired_capabilities=DesiredCapabilities.INTERNETEXPLORER)
return WEB_DRIVER
Now let's go change login_password_ok.csv, include new variables, test_number and browsers:
test_number,login, password, user_type, browsers 001,alex,test@2015,tester,IE 002,luis,luis123,senior tester,IE 003,admin,admin,admin,IE 004,daniel,daniel123,guest,IE 005, jaque,jaque@2015,leader,IE 006,luis,luis123,senior tester,FIREFOX 007,admin,admin,admin,FIREFOX 008,daniel,daniel123,guest,FIREFOX 009,alex,test@2015,tester,FIREFOX 010,jaque,jaque@2015,leader,FIREFOX 011,luis,luis123,senior tester,CHROME 012,admin,admin,admin,CHROME 013,daniel,daniel123,guest,CHROME 014,alex,test@2015,tester,CHROME 015,jaque,jaque@2015,leader,CHROME
Need import new classe, as follows:
from classes.browsers_test import *
Let's go now instantiate the class, as follows:
def setUp(self): self.test_browser = browsers()
In our test in login_test.py, need change a little, on function change to receive new variables, as follows:
def test_login_password_ok(self,test_number,tl_login,tl_password,user_type,browser_type):
For last, now set browser function and pass the browser variable and return instantiates the same.
self.driver = self.test_browser.setBrowser(browser_type)
Too let's go create a list with results of tests.
Test Ok:
list_result.append([test_number,"Passed"])Test Fail:
list_result.append([test_number,"Failed"])
Now new code with changes:
"""
Author: Reinaldo Mateus R J, Test version: 0.1
Fist Step - Imports modules, in Python code in one module gains access to the code in another module by
the process of importing.
Second Step - create function get_data in csv file.
Third Step - create class and function specific for test.
"""
import csv, unittest, time, os
from ddt import ddt, data, unpack
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from variables_test import *
from classes.browsers_test import *
global list_result
list_result = []
def get_data(file_name):
# create an empty list to store rows
rows = []
# open the CSV file
print file_name
data_file = open(file_name, "rb")
# create a CSV Reader from CSV file
reader = csv.reader(data_file)
# skip the headers
next(reader, None)
# add rows from reader to list
for row in reader:
rows.append(row)
return rows
# DDT consists of a class decorator @ddt (for your TestCase subclass)
@ddt
class LoginTestClass(unittest.TestCase,object):
def setUp(self):
self.test_browser = browsers()
# url base of website
self.base_url = BASE_URL
# Read the users in rows, and Passing variables tl_login,tl_password,user_type to function test_run.
@data(*get_data(PATH_TEST_OK))
# will automatically unpack tuples and lists into multiple arguments, and dictionaries into multiple
# keyword arguments.
@unpack
def test_login_password_ok(self,test_number,tl_login,tl_password,user_type,browser_type):
self.driver = self.test_browser.setBrowser(browser_type)
wait = WebDriverWait(self.driver, 90)
# Try three times if fail.
for i in range(3):
try:
self.driver.get(self.base_url+ LOGIN_PAGE)
elem = wait.until(lambda driver: driver.find_element_by_name("tl_login"))
# Send user name in tl_login field
elem.send_keys(tl_login)
# Next we are sending keys, this is similar to entering keys using your keyboard.
elem.send_keys(Keys.RETURN)
elem = self.driver.find_element_by_name("tl_password")
# Send password in tl_password field
elem.send_keys(tl_password)
# This is similar to entering keys using your keyboard.
elem.send_keys(Keys.RETURN)
time.sleep(DELAY_FAST)
# timeout five seconds
time.sleep(DELAY_FAST)
self.driver.get(self.base_url+ MAIN_MENU)
print "\nTest: ", test_number, tl_login, tl_password, user_type, browser_type
time.sleep(DELAY_FAST)
confirm = wait.until(lambda driver: driver.find_element_by_xpath\
("/html/body/div[2]/span[contains(text(),'"+user_type+"')]" ))
print confirm.text
elem_test = str(confirm.text)
time.sleep(DELAY_FAST)
# split text in two words in the string.
elem_test = elem_test.split(" ", 1)
time.sleep(DELAY_FAST)
print "Tag value: " + str(elem_test)
# compare second word with user_type
if elem_test[1] == "["+user_type+"]":
if (self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE)):
# Test - compare text expected with XPATH_TOP_TEXT_MAIN_PAGE in browser.
self.assertTrue((self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE).text\
== TOP_TEXT_MAIN_PAGE))
print "Test User " +user_type+ " Passed with success! Test Number: ", test_number
self.driver.get(self.base_url+ INDEX_MENU)
time.sleep(DELAY_HIGH)
screenshot = self.driver.get_screenshot_as_file(SCREEN_SAVE + tl_login + "_" + tl_password + "" + user_type +'.png')
print "Screenshot saved to: %s" % screenshot
list_result.append([test_number,"Passed"])
return True
else:
# Inform if not found the field expected.
time.sleep(DELAY_HIGH)
# Test - compare text expected with XPATH_TOP_TEXT_MAIN_PAGE in browser.
self.assertTrue((self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE).text\
== TOP_TEXT_MAIN_PAGE))
print "Element Xpath not found: ", tl_login, tl_password, user_type , browser_type
except:
pass
print "Failed! Test Number: ",test_number, tl_login, tl_password, user_type, browser_type
print "Failed attempts: ", i
if (i >= 2):
list_result.append([test_number,"Failed"])
time.sleep(DELAY_HIGH)
# Logout this web application
self.driver.get(self.base_url+ LOGOUT_PAGE)
def tearDown(self):
# function which returns a new sorted list
list_result.sort()
print "\nTest Number / Result "
for i in xrange(0,len(list_result)):
print "----------------------------------"
print list_result[i][0],list_result[i][1]
self.driver.close()
# will end the whole session.
#self.driver.quit()
To execution new test, need selenium-server-standalone-2.47.1.jar
Page to download: http://www.seleniumhq.org/download/
I created .bat file to run selenium-server in windows, follow the tip:
Create new file .txt in desktop and add commands below, rename the file to server selenium.bat
cd\
cd C:\selenium_server\
java -jar selenium-server-standalone-2.47.1.jar -port 4441
pause
Tests Result:
Test Number / Result
----------------------------------
001 Passed
----------------------------------
002 Passed
----------------------------------
003 Passed
----------------------------------
004 Passed
----------------------------------
005 Passed
----------------------------------
006 Passed
----------------------------------
007 Passed
----------------------------------
008 Passed
----------------------------------
009 Passed
----------------------------------
010 Passed
----------------------------------
011 Passed
----------------------------------
012 Passed
----------------------------------
013 Passed
----------------------------------
014 Passed
----------------------------------
015 Passed
The code is simple is efficient, could use the jenkins for this, but it's good to get out a bit outside the box to good results.
Now let's go the good practices, Refactoring the code.
create new class in classes directory with name:
common_functions.py
Put here all common functions:
__author__ = 'Reinaldo M. R. Junior'
import csv, unittest, time, os
class functions(object):
def get_data(self,file_name):
# create an empty list to store rows
rows = []
# open the CSV file
print file_name
data_file = open(file_name, "rb")
# create a CSV Reader from CSV file
reader = csv.reader(data_file)
# skip the headers
next(reader, None)
# add rows from reader to list
for row in reader:
rows.append(row)
return rows
Create class login in classes:
login.py
Perform Login is used by many classes, and the need to separate, to be used by other classes.
"""
Author: Reinaldo Mateus R J, Test version: 0.1
Fist Step - Imports modules, in Python code in one module gains access to the code in another module by
the process of importing.
Second Step - create function get_data in csv file.
Third Step - create class and function specific for test.
"""
import time
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from variables_test import *
class loginTest(object):
def test_login_password_ok(self,tl_login,tl_password,user_type,driver):
#self.test_browser = browsers()
# url base of website
self.base_url = BASE_URL
self.driver = driver
wait = WebDriverWait(self.driver, 90)
try:
self.driver.get(self.base_url+ LOGIN_PAGE)
elem = wait.until(lambda driver: driver.find_element_by_name("tl_login"))
# Send user name in tl_login field
elem.send_keys(tl_login)
# Next we are sending keys, this is similar to entering keys using your keyboard.
elem.send_keys(Keys.RETURN)
elem = self.driver.find_element_by_name("tl_password")
# Send password in tl_password field
elem.send_keys(tl_password)
# This is similar to entering keys using your keyboard.
elem.send_keys(Keys.RETURN)
time.sleep(DELAY_FAST)
# timeout five seconds
time.sleep(DELAY_FAST)
self.driver.get(self.base_url+ MAIN_MENU)
print "\nTest: ", tl_login, tl_password, user_type
time.sleep(DELAY_FAST)
confirm = wait.until(lambda driver: driver.find_element_by_xpath\
("/html/body/div[2]/span[contains(text(),'"+user_type+"')]" ))
print confirm.text
elem_test = str(confirm.text)
time.sleep(DELAY_FAST)
# split text in two words in the string.
elem_test = elem_test.split(" ", 1)
time.sleep(DELAY_FAST)
print "Tag value: " + str(elem_test)
# compare second word with user_type
if elem_test[1] == "["+user_type+"]":
time.sleep(DELAY_FAST)
return elem_test[1]
else:
return False
except (RuntimeError, TypeError, NameError):
print "Failed! Test Number: ",tl_login, tl_password, user_type
time.sleep(DELAY_HIGH)
pass
In variables_test.py create:
list_result = []
Now login_test.py, as follows:
"""
Author: Reinaldo Mateus R J, Test version: 0.1
Fist Step - Imports modules, in Python code in one module gains access to the code in another module by
the process of importing.
Second Step - create function get_data in csv file.
Third Step - create class and function specific for test.
"""
import unittest, time
from ddt import ddt, data, unpack
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from variables_test import *
from classes.browsers_test import *
from classes.common_functions import *
from classes.login import *
commom = functions()
login = loginTest()
# DDT consists of a class decorator @ddt (for your TestCase subclass)
@ddt
class LoginTestClass(unittest.TestCase,object):
def setUp(self):
self.test_browser = browsers()
# url base of website
self.base_url = BASE_URL
self.driver = ''
# Read the users in rows, and Passing variables tl_login,tl_password,user_type to function test_run.
@data(*commom.get_data(PATH_TEST_OK))
# will automatically unpack tuples and lists into multiple arguments, and dictionaries into multiple
# keyword arguments.
@unpack
def test_login_password_ok(self,test_number,tl_login,tl_password,user_type,browser_type):
self.driver = self.test_browser.setBrowser(browser_type)
wait = WebDriverWait(self.driver, 90)
# Try three times if fail.
for i in range(3):
try:
elem_test = login.test_login_password_ok(tl_login,tl_password,user_type,self.driver)
if elem_test == "["+user_type+"]":
if (self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE)):
# Test - compare text expected with XPATH_TOP_TEXT_MAIN_PAGE in browser.
self.assertTrue((self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE).text\
== TOP_TEXT_MAIN_PAGE))
print "Test User " +user_type+ " Passed with success! Test Number: ", test_number
self.driver.get(self.base_url+ INDEX_MENU)
time.sleep(DELAY_HIGH)
screenshot = self.driver.get_screenshot_as_file(SCREEN_SAVE + tl_login + "_" + tl_password + "" + user_type +'.png')
print "Screenshot saved to: %s" % screenshot
list_result.append([test_number,"Passed"])
return True
else:
# Inform if not found the field expected.
time.sleep(DELAY_HIGH)
# Test - compare text expected with XPATH_TOP_TEXT_MAIN_PAGE in browser.
self.assertTrue((self.driver.find_element_by_xpath(XPATH_TOP_TEXT_MAIN_PAGE).text\
== TOP_TEXT_MAIN_PAGE))
print "Element Xpath not found: ", tl_login, tl_password, user_type , browser_type
except:
pass
print "Failed! Test Number: ",test_number, tl_login, tl_password, user_type, browser_type
print "Failed attempts: ", i
if (i >= 2):
list_result.append([test_number,"Failed"])
time.sleep(DELAY_HIGH)
# Logout this web application
self.driver.get(self.base_url+ LOGOUT_PAGE)
def tearDown(self):
# function which returns a new sorted list
list_result.sort()
print "\nTest Number / Result "
for i in xrange(0,len(list_result)):
print "----------------------------------"
print list_result[i][0],list_result[i][1]
self.driver.close()
# will end the whole session.
self.driver.quit()
Now is the half the size it was, and still going be used for functions other classes, refactoring the code is good practice.
Another good practice is commit this code in version control system, below our code committed in bitbucket:
git clone https://reiload@bitbucket.org/reiload/selenium-webdriver-ddt-and-python-with-real-project.git
In the next Topic about Design Patterns in Selenium.
http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp
http://www.seleniumhq.org/docs/03_webdriver.jsp#webdriver-and-the-selenium-server