Using arg parser in python in another class - python

I'm trying to write a test in Selenium using python,
I managed to run the test and it passed, But now I want add arg parser so I can give the test a different URL as an argument.
The thing is that my test is inside a class,
So when I'm passing the argument I get an error:
app_url= (args['base_url'])
NameError: global name 'args' is not defined
How can I get args to be defined inside the Selenium class?
This is my code:
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
from selenium import webdriver
import unittest, time, re
import os
import string
import random
import argparse
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8))
agmuser = id_generator()
class Selenium(unittest.TestCase):
def setUp(self):
chromedriver = "c:\chromedriver.exe"
os.environ["webdriver.chrome.driver"] = chromedriver
self.driver = webdriver.Chrome(chromedriver)
app_url = (args['base_url'])
#app_url= "http://myd-vm16635.fufu.net:8080/"
print "this is the APP URL:" + ' ' + app_url
self.base_url = app_url
self.verificationErrors = []
self.accept_next_alert = True
def test_selenium(self):
#id_generator.user = id_generator()
driver = self.driver
driver.get(self.base_url + "portal/")
driver.find_element_by_css_selector("span").click()
driver.find_element_by_id("j_loginName").clear()
driver.find_element_by_id("j_loginName").send_keys(agmuser)
driver.find_element_by_id("btnSubmit").click()
driver.find_element_by_link_text("Login as" + ' ' + agmuser).click()
driver.find_element_by_css_selector("#mock-portal-Horizon > span").click()
# driver.find_element_by_id("gwt-debug-new-features-cancel-button").click()
# driver.find_element_by_xpath("//table[#id='gwt-debug-module-dropdown']/tbody/tr[2]/td[2]").click()
# driver.find_element_by_id("gwt-debug-menu-item-release-management").click()
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
#####################******SCRIPT PARAMS****;**###################################
# these values can be changed type 'python selenium_job.py --help' for assistance
##################################################################################
parser = argparse.ArgumentParser(description='DevOps team - Sanity test')
parser.add_argument('-b', '--base_url', help='base_url', default="http://myd-vm16635.fufu.net:8080/")
args = vars(parser.parse_args())
unittest.main()

Put the parser = argparse.ArgumentParser(...) and parser.add_argument() outside if __name__ == "__main__": so that it always gets created but not evaluated. Keep args = vars(parser.parse_args()) inside __main__.
That way you can import it from the file like from selenium_tests import parser and then in your other script, do parser.parse_args().
And a cleaner way to do it is to create a function which returns the parser, like:
def get_parsed_args():
parser = argparse.ArgumentParser(...)
parser.add_argument(...)
# etc.
args = parser.parse_args()
return args
# or just...
return parser.parse_args()
#and then call that in the main program:
if __name__ == '__main__':
args = get_parsed_args()
# etc.
And in other scripts which you want to import it into, do
from selenium_tests import get_parsed_args
if __name__ == '__main__':
args = get_parsed_args()
# etc.

Related

An element could not be located on the page using the given search parameters

Appium automation runs and ends correctly inside one class, but fails when another class is created.
I tried to to delete all attributes in init, except first one and it helps.
Main Class(works well)
import unittest
from appium import webdriver
from ScreenObjects.SendMessage import SendMsg
class AppTestAppium(unittest.TestCase):
def setUp(self):
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = ''
desired_caps['deviceName'] = '81e9b20e'
desired_caps['appPackage'] = 'org.telegram.messenger'
desired_caps['appActivity'] = 'org.telegram.ui.LaunchActivity'
desired_caps['noReset'] = 'True'
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
def tearDown(self):
"Tear down the test"
self.driver.quit()
def test_send_messge_to_olga(self):
"Test is sending message"
contactItem = self.driver.find_element_by_xpath("//android.view.ViewGroup[contains(#index,'2')]")
contactItem.click()
elementTypeField = self.driver.find_element_by_xpath("//android.widget.EditText[contains(#index,'1')]")
elementTypeField.clear()
elementTypeField.send_keys("Hello. If you are reading this, my first appium automation has passed")
sendButton = self.driver.find_element_by_xpath("//android.widget.ImageView[#content-desc ='Send']")
sendButton.click()
if __name__ == '__main__':
unittest.main()
Main class(fails)
import unittest
from appium import webdriver
from ScreenObjects.SendMessage import SendMsg
class AppTestAppium(unittest.TestCase):
def setUp(self):
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = ''
desired_caps['deviceName'] = '81e9b20e'
desired_caps['appPackage'] = 'org.telegram.messenger'
desired_caps['appActivity'] = 'org.telegram.ui.LaunchActivity'
desired_caps['noReset'] = 'True'
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub',desired_caps)
def tearDown(self):
"Tear down the test"
self.driver.quit()
def test_send_messge_to_olga(self):
"Test is sending message"
send_message = SendMsg(self.driver)
send_message.chooseContact()
send_message.typeMsg()
send_message.clickSend()
if __name__ == '__main__':
unittest.main()
with one more Class (fails)
class SendMsg(object):
def __init__(self, driver):
self.contactItem = driver.find_element_by_xpath("//android.view.ViewGroup[contains(#index,'2')]")
self.elementTypeField = driver.find_element_by_xpath("//android.widget.EditText[contains(#index,'1')]")
self.sendButton = driver.find_element_by_xpath("//android.widget.ImageView[#content-desc ='Send']")
def chooseContact(self):
self.contactItem.click()
def typeMsg(self):
self.elementTypeField.clear()
self.elementTypeField.send_keys("Hello")
def clickSend(self):
self.sendButton.click()
I expect TEST PASSED, but the actual output is 'An element could not be located on the page using the given search parameters.'

repetitive global variable and try except in python unit tests

I have started using Python Selenium and wrote a script shown below.
This prints a return code linked to the test that fails (test01, test02, test03, ..).
Ignore that each test is checking the same thing.
I'm just trying to understand if there's a cleaner way to write the tests because each one repetitively declares global res, and then has a try/except block.
Could anyone offer some advice on how to improve this please?
# global variable for return code. Zero is success.
res=0
#atexit.register
def send_health():
print ("res=%s") % res
class Login(unittest2.TestCase):
#classmethod
def setUpClass(inst):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
inst.driver = webdriver.Firefox(firefox_binary=binary)
inst.base_url = "https://stackoverflow.com"
def test01(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test01.png')
res=1
return
def test02(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test02.png')
res=2
return
def test03(self):
global res
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
print ("Exception: %s" % e)
driver.save_screenshot('screenshot_test03.png')
res=3
return
if __name__ == "__main__":
unittest2.main()
There is no need for global variables here at all. You are inside a class; use self.res throughout.
That's exactly what setUp instance method is for, quite similar to setUpClass method that is run once per test class.
def setUp(self):
# this code will be executed before each and every test
self.res = 0
def tearDown(self):
# this code will be executed post each and every test.
By the way, why are you using global variables? There's no need for them. In fact, there's seldom a valid rationale for using globals. Moreover, tests need to be isolated and independent, using global variables would violate that rule.
Thanks for the tips above. I've reduced the code down to this version which hopefully looks cleaner and more standard:
class Login(unittest2.TestCase):
#classmethod
def handleError(self, e, res):
print ("Test failed with exception: %s" % e)
self.result = res
sys.exit()
#classmethod
def setUpClass(self):
binary = FirefoxBinary('C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe')
self.driver = webdriver.Firefox(firefox_binary=binary)
self.base_url = "https://stackoverflow.com"
self.result = 0
def test01(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 1)
def test02(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 2)
def test03(self):
driver = self.driver
try:
self.assertEqual("Ask a Question", driver.title)
except Exception,e:
self.handleError(e, 3)
#classmethod
def tearDownClass(self):
self.driver.quit()
print ("res=%s") % self.result
if __name__ == "__main__":
unittest2.main()

Python Selenium Test Suite Single Webdriver Instance?

I'm having some real issues trying to work out how to get this to work, and I'm sure there are some experts on here who can work it out for me, please :)
So I have a number of test cases in python that all follow on from each other, but are individual scripts, I want to combine these and run them in order, in a single webdriver instance, as they all follow on, but I can't seem to work out how to do it..
I have created a test suite -
import unittest
from Searchfieldreturnscorrectvalue import SearchFieldReturnsCorrectValue
from Navigatetostreetlightprecontentpage import Navigatetostreetlightprecontentpage
class TestSuite(unittest.TestSuite):
def suite():
suite = unittest.TestSuite()
suite.addTest(Searchfieldreturnscorrectvalue('test_searchfieldreturnscorrectvalue'))
suite.addTest(Navigatetostreetlightprecontentpage('test_navigatetostreetlightprecontentpage'))
return suite
if __name__ == "__main__":
unittest.main()
This runs the tests, but the second one fails as it tried to run it in a second firefox instance..
Searchfieldreturnscorrectvalue.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class SearchFieldReturnsCorrectValue(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.XXXXX.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_search_field_returns_correct_value(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("edit-search-block-form--2").click()
driver.find_element_by_id("edit-query").clear()
driver.find_element_by_id("edit-query").send_keys("street light")
driver.find_element_by_id("edit-query").send_keys(Keys.ENTER)
for i in range(60):
try:
if self.is_element_present(By.LINK_TEXT, "Street lighting"): break
except: pass
time.sleep(1)
else: self.fail("time out")
try: self.assertEqual("Street lighting", driver.find_element_by_link_text("Street lighting").text)
except AssertionError as e: self.verificationErrors.append(str(e))
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
Navigatetostreetlightprecontentpage.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Navigatetostreetlightprecontentpage(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.verificationErrors = []
self.accept_next_alert = True
def test_navigatetostreetlightprecontentpage(self):
driver = self.driver
driver.find_element_by_link_text("Street lighting").click()
try: self.assertEqual("Street lighting", driver.find_element_by_css_selector("h1.page-title__main__title").text)
except AssertionError as e: self.verificationErrors.append(str(e))
try: self.assertEqual("Report a faulty street light | Cheshire East", driver.title)
except AssertionError as e: self.verificationErrors.append(str(e))
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
I don't know if a test suite is the correct way to do it, or to just get all the tests into one file, but I still would want the "Classes/Tests" to individually report pass/fail, at the moment I can't get that to work, I think it is something to do with the setUp(self) needing to be moved to a setUpModule and shared? But I can't work it out, if someone could please point me in the right direction, I would be very grateful.
Thanks
Update
Example of what I have tired as per comment bellow, still not working..
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class SeleniumTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
cls.driver.maximize_window()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class SearchFieldReturnsCorrectValue(SeleniumTest):
def setUp(cls):
cls.base_url = "https://www.XXXXX.com"
cls.verificationErrors = []
cls.accept_next_alert = True
def test_search_field_returns_correct_value(cls):
driver = cls.driver
driver.get(cls.base_url + "/")
driver.find_element_by_id("edit-search-block-form--2").click()
driver.find_element_by_id("edit-query").clear()
driver.find_element_by_id("edit-query").send_keys("street light")
driver.find_element_by_id("edit-query").send_keys(Keys.ENTER)
for i in range(60):
try:
if cls.is_element_present(By.LINK_TEXT, "Street lighting"): break
except: pass
time.sleep(1)
else: cls.fail("time out")
try: cls.assertEqual("Street lighting", driver.find_element_by_link_text("Street lighting").text)
except AssertionError as e: cls.verificationErrors.append(str(e))
driver.find_element_by_link_text("Street lighting").click()
def is_element_present(cls, how, what):
try: cls.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(cls):
try: cls.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(cls):
try:
alert = cls.driver.switch_to_alert()
alert_text = alert.text
if cls.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: cls.accept_next_alert = True
def tearDown(cls):
cls.assertEqual([], cls.verificationErrors)
class Navigatetostreetlightprecontentpage(SeleniumTest):
def setUp(cls):
cls.verificationErrors = []
cls.accept_next_alert = True
def test_navigatetostreetlightprecontentpage(cls):
driver = cls.driver
try: cls.assertEqual("Street lighting", driver.find_element_by_css_selector("h1.page-title__main__title").text)
except AssertionError as e: cls.verificationErrors.append(str(e))
try: cls.assertEqual("Report a faulty street light | Cheshire East", driver.title)
except AssertionError as e: cls.verificationErrors.append(str(e))
def is_element_present(cls, how, what):
try: cls.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(cls):
try: cls.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(cls):
try:
alert = cls.driver.switch_to_alert()
alert_text = alert.text
if cls.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: cls.accept_next_alert = True
def tearDown(cls):
cls.assertEqual([], cls.verificationErrors)
if __name__ == "__main__":
unittest.main()
This seems to be running both classes now, but the second class is never able to locate any elements, but the same line in the first class works perfectly.
I am not sure I understood well, but to use a single driver instance, you can use the setupClass class method where you create the driver:
class MyTestClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
def setUp(self):
....
It will still recreate the driver for every new test class, but it does not recreate one for every test (as setUp does).
Personnally I make all my test classes inherit from a SeleniumTest class like this:
class SeleniumTest(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.driver = webdriver.Firefox()
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class MyTestClass(SeleniumTest):
def setUp(self):
....
import unittest
from selenium import webdriver
from time import sleep
class SeleniumTest(unittest.TestCase):
global driver
#classmethod
def setUpClass(cls):
#getting a common webdriver instance for all your tests for this module
cls.driver = webdriver.Chrome("/Users/sibasish/PycharmProjects/CommonDriverInstance/chromedriver")
cls.driver.get("https://www.google.com")
#classmethod
def tearDownClass(cls):
cls.driver.close()
cls.driver.quit()
class MyTestClass(SeleniumTest):
def setUp(self):
pass
def test_sample1(self):
print("hello1")
self.driver.get("https://www.google.com/")
sleep(4)
def test_sample2(self):
print("hello2")
self.driver.get("https://www.facebook.com/")
sleep(4)

Checking if HTML element exists with Python Selenium

I am trying to check if an element exists on an HTML page with Selenium/Python.
This is my function:
class runSelenium(object):
def __init__(self):
# define a class attribute
self.driver = webdriver.Firefox()
def isElementPresent(self, locator):
try:
self.driver.find_element_by_xpath(locator)
except NoSuchElementException:
print ('No such thing')
return False
return True
def selenium(self):
self.driver.get("https://somepage.com")
isElement = self.isElementPresent("//li[#class='item'][6]")
isElement1 = str(isElement)
if __name__ == '__main__':
run = runSelenium()
run.selenium()
I am trying to pick the result with a Boolean value but with no luck:
isElement = self.isElementPresent("//li[#class='item'][6]")
What am I missing here?
You need to un-indent the last code block:
class runSelenium(object):
def __init__(self):
# define a class attribute
self.driver = webdriver.Firefox()
def isElementPresent(self, locator):
try:
self.driver.find_element_by_xpath(locator)
except NoSuchElementException:
print ('No such thing')
return False
return True
def selenium(self):
self.driver.get("https://somepage.com")
isElement = self.isElementPresent("//li[#class='item'][6]")
isElement1 = str(isElement)
if __name__ == '__main__':
run = runSelenium()
run.selenium()
So I restarted the IDE (Visual Studio 2013) and it works now fine.. The code is correct 100%

How to input parameters into Selenium RC TestSuite?

I have to test few sites which sales the same things, but they have an another template.
So I want to run each MainTestClass with giving some input parameter, let's say :
java -jar SeleniumServerStandalone-2.0b2.jar -port 5555 (template_id=5)
Is it possible?
class MainTestCases(unittest.TestCase):
def setUp(self):
#self.template_id=template_id I want something like that
self.verificationErrors = []
self.selenium = selenium("localhost", 5555, "*chrome", "http://www.google.com/")
time.sleep(5)
self.selenium.start()
def test_test1(self):
if self.template_id==1:
...
elif self.template_id==2:
...
def test_test2(self):
if self.template_id==1:
...
elif self.template_id==2:
...
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
Try adding an init method to MainTestCases, like so:
class MainTestCases(unittest.TestCase):
def __init__(self, methodName, template_id):
super(MainTestCases, self).__init__(self, methodName)
self.template_id = templateId
def setUp(self):
... and so on...
Due to this customization, you will need to build your test suite manually because each test case has to be instantiated with the template_id, like so--
def suite(template_id):
testcasenames = unittest.defaultTestLoader.loadTestsFromTestCase(MainTestCases)
suite = []
for case in testcasename:
suite.append(MainTestCases(case, template_id)
return suite
Then in main, instead of unittest.main(), do:
Parse command-line arguments. You may want to consider the argparse (2.7+) or optparse (2.6 and earlier) modules. They are powerful, but easy to start with by looking at the examples.
Create and run the suite: unittest.TextTestRunner().run(suite(template_id))
Now, I use this solution:
Create suite test which runs testcases:
import unittest
from Flights.FlightsTestCases import FlightsTestCases
import sys
from Flights.FlightTemplate import FlightTemplate
def suite():
testSuite= unittest.TestSuite()
testSuite.addTest(FlightsTestCases('test_test1'))
FlightsTestCases.www_address='http://testpage.pl/'
FlightsTestCases.flight_template=FlightTemplate.Test
#FlightsTestCases.www_address='http://productionpage.pl/'
#FlightsTestCases.flight_template=FlightTemplate.Production
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
change set_up to something like:
class FlightsTestCases(unittest.TestCase):
www_address = None
flight_template = None
xml_report_generator = None
def setUp(self):
self.verificationErrors = []
if self.www_address == None:
self.selenium = selenium("localhost", 5555, "*chrome", "http://testpage.pl/")
else:
self.selenium = selenium("localhost", 5555, "*chrome", self.www_address)

Categories