I have a class with few tests, for example:
class Example(Environment)
def test1(self):
def test2(self):
def test3(self):
def test4(self):
and class environment with setup and teardown methods
class Environment(unittest.TestCase):
def setUp(self):
options_for_console_log = DesiredCapabilities.CHROME
options_for_console_log['loggingPrefs'] = {'browser': 'ALL'}
self.driver = webdriver.Chrome(desired_capabilities=options_for_console_log)
self.driver.maximize_window()
def tearDown(self):
driver = self.driver
driver.close()
After every test chrome reopens, but i want to run it in one session. How can i do it?
setUp and tearDown are called before and after every test method. If you want driver to persist between tests move the relevant code to setUpClass and tearDownClass:
#classmethod
def setUpClass(cls):
options_for_console_log = DesiredCapabilities.CHROME
options_for_console_log['loggingPrefs'] = {'browser': 'ALL'}
cls.driver = webdriver.Chrome(desired_capabilities=options_for_console_log)
cls.driver.maximize_window()
#classmethod
def tearDownClass(cls):
cls.driver.close()
Just make sure that all the test cases are independent and standalone.
Related
Hi I'm trying to learn Python/Selenium using a Page Object Model.
I have been following this tutorial and as far as I can tell I haven't missed anything. However I can't run my tests because of the init constructor. In the video, he has the same init constructor and the tests run for him.
Inside my project folder I have a subfolder pageObjects and testCases.
In pageObjects I have LoginPage.py where i set up my locators and actions i want to perform on the locators
class LoginPage:
textbox_username_id = "Email"
textbox_password_id = "Password"
button_login_xpath = "//input[#class='button-1 login-button']"
link_logout_linktext = "Logout"
def __init__(self,driver):
self.driver = driver
def setUserName(self,username):
self.driver.find_element_by_id(self.textbox_username_id).clear()
self.driver.find_element_by_id(self.textbox_username_id).send_keys(username)
def setPassword(self,password):
self.driver.find_element_by_id(self.textbox_password_id).clear()
self.driver.find_element_by_id(self.textbox_password_id).send_keys(password)
def clickLogin(self):
self.driver.find_element_by_xpath(self.button_login_xpath).click()
def clickLogout(self):
self.driver.find_element_by_link_text(self.link_logout_linktext).click()
In testCases I have test_login.py and conftest.py
I'll show conftest.py first
from selenium import webdriver
import pytest
#pytest.fixture()
def setup():
driver = webdriver.Chrome()
return driver
and test_login.py
import pytest
from selenium import webdriver
from pageObjects.LoginPage import LoginPage
from testCases import conftest
class Test_001_Login:
baseURL = "https://admin=demo.nopcommerce.com/"
username = "admin#yourstore.com"
password = "admin"
def __init__(self):
self.lp = LoginPage(self.driver)
self.driver = conftest.setup
def test_homePageTitle(self, setup):
self.driver = setup
self.driver.get(self.baseURL)
act_title = self.driver.title
self.driver.close()
if act_title == "Your store. Login":
assert True
else:
assert False
def test_login(self, setup):
self.driver = setup
self.driver.get(self.baseURL)
self.lp.setUserName(self.username)
self.lp.setPassword(self.password)
self.lp.clickLogin()
act_title = self.driver.title
if act_title == "Dashboard / nopCommerce administration":
assert True
else:
assert False
There are 2 issues.
conftest.py is supposed to be a special type of class/fixture. I should be able to call it to create an instance of webdriver.Chrome(). However it does not work. In test_login.py when i call 'setup' I get an error 'unresolved reference 'setup''. So I've had to manually import it as a work around. Isn't the whole point of the conftest.py file so that my test_* files have access to the webdriver in conftest.py wihtout having to import it?
When i try to run the test_login.py file, I get a warning and 0 items are collected - testCases\test_login.py:6
C:\Users\Mirza\PycharmProjects\nopcommerceApp\testCases\test_login.py:6: PytestCollectionWarning: cannot collect test class 'Test_001_Login' because it has a init constructor (from: testCases/test_login.py)
class Test_001_Login:
I have absolutely no idea what to do here. Why can't my class Test_001_Login have an init constructor? I need it to create an instance of the LoginPage class and to create an instance of the webdriver from conftest.py.
Any help would be greatly appreciated.
I am using sample code with unittest but I receive an error when I execute it -- 'str' object has no attribute 'get'.
I searched Google but did not get an answer.
from selenium import webdriver
import unittest
class google1search(unittest.TestCase):
driver = 'driver'
#classmethod
def setupClass(cls):
cls.driver = webdriver.Chrome(chrome_options=options)
cls.driver.implicitly_wait(10)
cls.driver.maximize_window()
def test_search_automationstepbystep(self):
self.driver.get("https://google.com")
self.driver.find_element_by_name("q").send_keys("Automation Step By step")
self.driver.find_element_by_name("btnk").click()
def test_search_naresh(self):
self.driver.get("https://google.com")
self.driver.find_element_by_name("q").send_keys("Naresh")
self.driver.find_element_by_name("btnk").click()
#classmethod
def teardownClass(cls):
cls.driver.close()
cls.driver.quit()
print("Test completed")
if __name__== "__main__":
unittest.main()
Supposed to execute 2 steps and give result pass.
In the above code :
There is no initialization of self.driver for
self.driver.get("https://google.com")
as the driver initiated is for
cls.driver = webdriver.Chrome(chrome_options=options)
please replace cls with self
I want to extend #sarthak response little bit. In the sample code methods setUpClass and tearDownClass are used. These methods are called to prepare test class and called only once before executing all test in your test class.
Which can work in your case because at the beginning of each test you're overwriting internal state of the driver object and your previous test execution shouldn't affect your next test result. In this case you need to modify your tests to use class object:
def test_search_automationstepbystep(self):
TestClass.driver.get("https://google.com")
TestClass.driver.find_element_by_name("q").send_keys("Automation Step By step")
TestClass.driver.find_element_by_name("btnk").click()
def test_search_naresh(self):
TestClass.driver.get("https://google.com")
TestClass.driver.find_element_by_name("q").send_keys("Naresh")
TestClass.driver.find_element_by_name("btnk").click()
Where TestClass is the name of your test class.
The other option is to use setUp and tearDown methods to initialize driver object before each test case:
def setUp(self):
self.driver = webdriver.Chrome(chrome_options=options)
self.driver.implicitly_wait(10)
self.driver.maximize_window()
def tearDown(self):
self.driver.close()
self.driver.quit()
print("Test completed")
Both setUp and tearDown methods accept instance of TestClass as self argument and your tests should work without any additional changes.
Note: Usually second option is preferable for unit testing, cause you don't need to make sure in every test that you overwrite driver internal state before using find_element_by_name. And in second option you can put self.driver.get("https://google.com") code into setUp method, cause it's going to be executed before each test case anyway.
I am trying to build an selenium based automation framework, using, Python, Pytest.
My intention is to create a driver instance at the class level by initializing it in conftest.py and making it available in all testcases, so that user doesn't need to create the driver instance in each testcase.
Driver instance in conftest.py:
#pytest.fixture(scope="class")
def get_driver(request):
from selenium import webdriver
driver = webdriver.Chrome()
request.cls.driver = driver
yield
driver.quit()
BaseTestCase class looks like this:
#pytest.mark.usefixtures("get_driver")
class BaseTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(BaseTestCase, self).__init__(*args, **kwargs)
#classmethod
def setUpClass(cls):
if hasattr(super(BaseTestCase, cls), "setUpClass"):
super(BaseTestCase, cls).setUpClass()
My testcase is as follows:
from ..pages.google import Google
class Test_Google_Page(BaseTestCase):
#classmethod
def setUpClass(self):
self.page = Google(self.driver, "https://www.google.com/")
My page Google extends to BasePage that looks like this:
class BasePage(object):
def __init__(self, driver, url=None, root_element = 'body'):
super(BasePage, self).__init__()
self.driver = driver
self._root_element = root_element
self.driver.set_script_timeout(script_timeout)
When i execute my testcase, I get the following error:
#classmethod
def setUpClass(self):
> driver = self.driver
E AttributeError: type object 'Test_Google_Page' has no attribute 'driver'
How can I make the driver instance available in my testcases by simply calling self.driver?
The class scoped fixtures are executed after the setUpClass classmethods, so when Test_Google_Page.setUpClass is executed, get_driver did not run yet. Check out the execution ordering:
import unittest
import pytest
#pytest.fixture(scope='class')
def fixture_class_scoped(request):
print(f'{request.cls.__name__}::fixture_class_scoped()')
#pytest.mark.usefixtures('fixture_class_scoped')
class TestCls(unittest.TestCase):
#classmethod
def setUpClass(cls):
print(f'{cls.__name__}::setUpClass()')
def setUp(self):
print(f'{self.__class__.__name__}::setUp()')
#pytest.fixture()
def fixture_instance_scoped(self):
print(f'{self.__class__.__name__}::fixture_instance_scoped()')
#pytest.mark.usefixtures('fixture_instance_scoped')
def test_bar(self):
print(f'{self.__class__.__name__}::test_bar()')
assert True
When running the test with e.g. pytest -sv, the output yields:
TestCls::setUpClass()
TestCls::fixture_class_scoped()
TestCls::fixture_instance_scoped()
TestCls::setUp()
TestCls::test_bar()
So the solution is to move the code from setUpClass to e.g. setUp:
class Test_Google_Page(BaseTestCase):
def setUp(self):
self.page = Google(self.driver, "https://www.google.com/")
I am afraid I may not use setUp because in my most of my class file I have multiple test cases and I just want to do one time setup in setUpClass instead of launching in each time before calling any test method.
I would then move the code from setUpClass to another class-scoped fixture:
import pytest
#pytest.mark.usefixtures('get_driver')
#pytest.fixture(scope='class')
def init_google_page(request):
request.cls.page = Google(request.cls.driver,
"https://www.google.com/")
#pytest.mark.usefixtures('init_google_page')
class Test_Google_Page(BaseTestCase):
...
The former setUpClass is now the init_google_page fixture which will be called after get_driver (because of pytest.mark.usefixtures('get_driver')).
I want to create a selenium test using functions and classes. The first file and first class is:
import unittest
import time
from selenium import webdriver
class DriverAndLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
def test_login(self):
driver = self.driver
driver.get('https://qa.knolyx.com/')
self.assertIn("Login to your account | Knolyx", driver.title)
time.sleep(1)
search_box = driver.find_element_by_name('email')
search_box.send_keys('username#test.com')
password = driver.find_element_by_name('password')
password.send_keys("98765")
button_login = driver.find_element_by_css_selector('#app > div > div > form > div.Login_Actions > button')
button_login.click()
time.sleep(1)
self.assertIn("Dashboard | Knolyx", driver.title)
if __name__ == "__main__":
unittest.main()
I want to create another file and class to continue first file and class. So, the code above acces the Knolyx site and login, and my second file I want to continue from login forwards.
I tried with:
from SeleniumOOP import DriverAndLogin
import unittest
import time
class ChangeRole(unittest.TestCase, DriverAndLogin):
But the variable "self.driver" or "driver" is not visible in second file.
P.S:
I tried with:
from SeleniumOOP.DriverAndLogin import DriverAndLogin
import unittest
from selenium import webdriver
class ChangeRole(unittest.TestCase, metaclass=DriverAndLogin):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
def see_the_role(self):
driver = self.driver
therole = driver.find_element_by_class_name('Person_Title').text
print(therole)
if __name__ == "__main__":
unittest.main()
But I get the error: "TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases"
It seems like you aren't calling ChangeRole.setUp() before trying to access self.driver.
class ChangeRole(DriverAndLogin):
def printDriver(self):
print(self.driver)
if __name__ == "__main__":
ch = ChangeRole()
ch.setUp()
ch.printDriver()
This should work as intended.
If you don't want to call setUp before, you should consider adding it to your __init__ function:
class ChangeRole(DriverAndLogin):
def __init__(self):
self.setUp()
def printDriver(self):
print(self.driver)
This way, setUp() is called every time an instance of the class is created. Depending on what you want to do with the DriverAndLogin class, it might also be a good idea to add a call to setUp() to DriverAndLogin.__init__.
Ok, what you really want to do (the real problem, not what you think is the solution) is to 1. test that you can login and 2. test that if you're logged in you can "see the role".
The solution here is not to "have a class that continue where the first has stopped" (which makes no sense at all), but to have two test methods in your TestCase class and factor out the login part:
class MyTestCase(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
# this is a normal method and won't be called
# directly by the test runner
def login(self):
driver = self.driver
driver.get('https://qa.knolyx.com/')
self.assertIn("Login to your account | Knolyx", driver.title)
time.sleep(1)
search_box = driver.find_element_by_name('email')
search_box.send_keys('username#test.com')
password = driver.find_element_by_name('password')
password.send_keys("98765")
button_login = driver.find_element_by_css_selector('#app > div > div > form > div.Login_Actions > button')
button_login.click()
time.sleep(1)
def test_login(self):
self.login()
self.assertIn("Dashboard | Knolyx", self.driver.title)
def test_can_see_role(self):
self.login()
driver = self.driver
therole = driver.find_element_by_class_name('Person_Title').text
print(therole)
A TestCase can have has many tests as you want, each will be executed in isolation by the testrunner, so technically you do not need two different classes nor two different files. You can also have as many testcases as you want in a same file.
Now if you really want to split this in different testcases (and eventually in different files), define a mixin class with the common parts (here the setUp and login method and use multiple inheritance:
class DriverAndLoginMixin(object):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
# this is a normal method and won't be called
# directly by the test runner
def login(self):
driver = self.driver
driver.get('https://qa.knolyx.com/')
self.assertIn("Login to your account | Knolyx", driver.title)
time.sleep(1)
search_box = driver.find_element_by_name('email')
search_box.send_keys('username#test.com')
password = driver.find_element_by_name('password')
password.send_keys("98765")
button_login = driver.find_element_by_css_selector('#app > div > div > form > div.Login_Actions > button')
button_login.click()
time.sleep(1)
class LoginTest(DriverAndLoginMixin, unittest.TestCase):
def test_login(self):
self.login()
self.assertIn("Dashboard | Knolyx", self.driver.title)
class AnotherTest(DriverAndLoginMixin, unittest.TestCase):
def test_can_see_role(self):
self.login()
driver = self.driver
therole = driver.find_element_by_class_name('Person_Title').text
print(therole)
I'm trying to retrieve the session id of a selenium webdriver session during the execution of a test as such:
import unittest
class MyTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
def testSomething(self):
"""selenium tests go here"""
self.driver.get('http://www.example.com')
def tearDown(self):
self.driver.quit()
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(MyTest)
testResult = unittest.TextTestRunner(verbosity=2).run(suite)
session_id = ???
I know I could do self.driver.session_id side the setUp method. The problem is I need to get the session id outside of the class instance. Any ideas?
Probably, you can create property/function inside the class instance which could return you sessionID.