I want to wrap the selenium webdriver in my own class, that each time I will call a method from my class it will handle calling and error handling to the webdriver class. what is the correct way to do it ?
class myClass():
browser = ... selenium web driver ...
def find_element_by_xpath(self, value):
try
browser.find_element_by_xpath(value)
except:
....
can myClass have the same method name ?
There are multiple valid ways to handle the calling and error handling of the webdriver class and yours should be fine.
Yes, myClass can have the same method names but you need to make sure you're calling the right thing. E.g
myClassInstance = myClass()
myClassInstance.find_element_by_xpath('thing')
will call browser.find_element_by_xpath just fine
Related
I'm making a program that automatically enters to a website and login(basically using selenium and chrome webdriver). User can type own information(id&pw) and site address in a dialog(used PyQt4 module). After finishing it, pressing ok button will execute it.
After logging in, I want to do some other actions with that webdriver objects.
So my question is, how can I pass the webdriver object to the main thread(which is UI thread here) so that I can do some other actions(such as logging out, etc), or how to manage that webdriver object generated in other thread in main thread?
I'm using Python3.7.4 and PyQt4 version.
I googled similar questions and found that it might be related with signal&slots.
so I tried to imitate this example (https://nikolak.com/pyqt-threading-tutorial/) which uses custom signal.
In this example, it passes a QString instance to the main thread(UI thread).
So I tried to pass my webdriver object by imitating it, but It's not going well...
The basic structure of code is following:
class MyDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
# and some codes with widget layouts
def btnOkClicked(self):
a = [self.editSite1.text(), self.editId.text(), self.editPw.text()]
self.gothread = goWebsiteThread(a)
# 'goWebsiteThread' is a thread that generates webdriver object and executes login function
self.connect(self.gothread, SIGNAL("add_driver(PyQt_PyObject)"), self.add_driver)
# this line is what I tried to pass the driver object to this main thread
self.gothread.start()
class goWebsiteThread(QThread, QObject):
# I tried to pass this class's object by making this class inherit QObject class... sorry for unfounded try..
def __init__(self, sites):
QThread.__init__(self)
self.sites = sites
def goWebsite(self):
self.driver = webdriver.Chrome('./chromedriver.exe', options=options)
self.driver.get(some site address that user typed)
# and codes to log in
self.emit(SIGNAL('add_driver(PyQt.PyObject)'), self.driver)
# I tried to pass the driver object by emitting signal...
def run(self):
self.goWebsite()
But this doesn't work (MyDialog object doesn't recognize the driver object).
How can I properly pass the webdriver object to MyDialog object and use it?
Webdriver should run on a new thread and it would be impossible to control webdriver from a UI thread.
But you can still store the webdriver as a member variable of the UI instance.
If you want to send some commands to the webdriver, you would need to start a new thread and handle automation works in the newly created thread.
I'm not very experience with writing classes and somewhat confused by their behavior.
test.py
class Profile:
def __init__(self):
self.browser = webdriver.Chrome()
def browser_object(self):
return webdriver.Chrome()
from the terminal:
from test import Profile
# I thought this would initialize webdriver.Chrome() and a browser window would pop up
x = Profile.browser_object()
# trying to access the webdriver so I can do something like
x.get(url) #from the terminal
No browser window is popping up. When I run x I see that it is a <function Profile.browser_object ...>
What am I doing wrong?
Try changing your other script to actually make an instance of the class you defined in test.py.
from test import Profile
profile_instance = Profile() # make an instance
browser_I_made = profile_instance.browser_object() # you probably wouldn't do this, but it's possible
I don't think you understand that a class is like a factory and you get "instances" of that object off the assembly line like in profile_instance = Profile()
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class CorrecaoEfetivaNota(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome('/Users/r13/dev/chromedriver')
def teste_login_avaliador(self):
driver = self.driver
driver.get("")
cpf = driver.find_element_by_xpath('//input[#placeholder="CPF"]')
cpf.send_keys("")
password = driver.find_element_by_xpath('//input[#placeholder="SENHA"]')
password.send_keys("")
login = driver.find_element_by_tag_name('button')
login.click()
driver.implicitly_wait(3)
def teste_buscar_mais_um(self):
driver = self.driver
buscar = driver.find_element_by_xpath("//section[1]/div/div/section[2]/div/div/div[1]/div/div[2]/button")
buscar.click()
def tearDown(self):
self.driver.close()
I'm trying to write this tests in Python, the first function is ok, but the second one inside the class is not being executed in the tests. How can I organize this?
While working with Python and unittest module with Selenium you have to consider a few facts as follows :
Indentation for class and test_method are different.
Instead of driver.close() always invoke driver.quit() within tearDown(){} method to close & destroy the WebDriver and Web Client instances gracefully.
If you are using unittest module you have to call the __main__.
Here is your own code with the required minor modifications which will execute the first method teste_login_avaliador() as well as the second method teste_buscar_mais_um() within the Class CorrecaoEfetivaNota():
import unittest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class CorrecaoEfetivaNota(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome(executable_path=r'C:\WebDrivers\chromedriver.exe')
def teste_login_avaliador(self):
driver = self.driver
driver.get("http://d3dyod5mwyu6xk.cloudfront.net/")
cpf = driver.find_element_by_xpath('//input[#placeholder="CPF"]')
cpf.send_keys("27922797885")
password = driver.find_element_by_xpath('//input[#placeholder="SENHA"]')
password.send_keys("enccejaregular")
login = driver.find_element_by_tag_name('button')
login.click()
driver.implicitly_wait(3)
def teste_buscar_mais_um(self):
driver = self.driver
buscar = driver.find_element_by_xpath("//section[1]/div/div/section[2]/div/div/div[1]/div/div[2]/button")
buscar.click()
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
unittest.main()
Note: Though both the test_methods are being called still you will face the following exception:
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"//section[1]/div/div/section[2]/div/div/div[1]/div/div[2]/button"}
At the line:
buscar = driver.find_element_by_xpath("//section[1]/div/div/section[2]/div/div/div[1]/div/div[2]/button")
This exception can be solved easily following the actual Test Steps of your usecase and if required you can raise a new question/ticket.
You write that the first function is ok, which I assume must be the setUp() function you are referring to (provided that in your code you indented correctly).
As Andersson comments, your unittest methods needs to begin with "test_" not "teste_". Providing "test_" is your way of telling unittest that this method should be tested.
In your unittest you probably also want to test something such as self.assertEqual(1,1) otherwise your tests will pass no matter what.
Next time please provide us with a more thorough description of what is wrong. How did you make the call to unittest? What error is python giving you? What result did you expect? Etc. It makes solving your problem much faster.
I encourage you to make a simple test first and ensure that it runs:
import unittest
class TestingUnittest(unittest.TestCase):
def setUp(self):
print("SetUp called")
def tearDown(self):
print("tearDown called")
def test_Method(self):
print("Testing 1==1")
self.assertEqual(1,1)
Call this from your terminal:
>>>python -m unittest "name-of-test.py"
I am new in python and I started to create an automation test suite about a GUI(multiple test cases in different file). I want to execute all my test cases in one selenium webdriver, so I created a singleton webdriver class and I want to use this class all my test cases. Here is my singleton webdriver class:
from selenium import webdriver
class Webdriver(object):
"""
Singleton class based on overriding the __new__ method
"""
def __new__(cls):
"""
Override __new__ method to control the obj. creation
:return: Singleton obj.
"""
if not hasattr(cls, 'instance'):
cls.instance = super(Webdriver, cls).__new__(cls)
return cls.instance
#staticmethod
def get_driver():
"""
:return: Selenium driver
"""
dir = "C:\\Python36\\Lib\\site-packages\\selenium\\webdriver\\ie"
ie_driver_path = dir + "\\IEDriverServer.exe"
return webdriver.Ie(ie_driver_path)
and my setUp example:
from Core.Webdriver import Webdriver
class LoginExternal(unittest.TestCase):
def setUp(self):
# Create Instances
self.web = Webdriver.get_driver()
self.matcher = TemplateMatcher()
self.gif = GifCapture("C:\\wifi\\Videos\\" + self._testMethodName + ".gif")
self.gif.start()
time.sleep(3)
def test_LoginExternal(self):
# Open External Login Page
self.web.maximize_window()
Here is my problem, when I execute my test suite, my code create a new selenium instance but I want only one selenium instance to be used in all test cases.
I use pytest as a test runner with following cmd command:
pytest --pyargs --html=Report/External_04052018.html ExternalTestSuite/
I think the problem is pytest use a new proccess in every test case execution. Is there any way to prevent or use like this way?
Pytest greatest feature and advantage over traditional XUnit family test runners is that it has fixtures. I invite you to use it. In your scenario, I would get rid of extending unittest.TestCase and setUp method in favor of pytest fixture as follows:
import pytest
from Core.Webdriver import Webdriver
class TestLoginExternal:
#pytest.fixture(scope='class')
def driver(self):
print('Setup runs once before all tests in class')
driver = Webdriver.get_driver()
yield driver
driver.quit()
print('Teardown runs once after all tests in class')
def test_LoginExternal(self, driver):
# Open External Login Page
print('test_LoginExternal')
def test_LoginInternal(self, driver):
# Open External Login Page
print('test_LoginInternal')
I am implementing the following class:
class TestInitializeConnection(TestMyDriver)
The super class (TestMyDriver) is a TestCase, meaning:
class TestMyDriver(test.TestCase):
the super class has an attribute named driver that basically is sort of a mock of the tested driver and it declared as follows:
self.driver = mocks.MyDriver()
now In my (TestInitializeConnection) I want to implement the following test:
def test_initialize_connection(self):
self.driver.initialize_connection(self.volume, self.connector)
Somewhere in the code of the function initialize_connection, there is a private method that is being called
specs = self._get_specs(volume)
and I want to make my test to tell this call of _get_specs(volume) to return a specific value, for example a dictionary with the value:
{'iops': 100, 'bandwith': 200}
What is the best way of doing so?
Thanks,
Matan
Just mock it out.
def test_initialize_connection(self):
with mock.patch.object(
self.driver,
'_get_specs',
return_value='your_fake_value') as mock_specs:
# Do something with self.driver