To answer one of your questions -- driver gets opened twice because you have two different setUp() methods, one for each of your classes - LoginTest and LegalPersonSearchTest. When you run test_valid_login, your setUpClass() method gets called, which initializes the driver. Then, test runs. This driver instance never gets torn down, so window remains open.
Then, test_valid_organization_search runs. This class ALSO has its own setUpClass() method, which initializes another driver instance. So now you have two drivers, both of which are opened in the setUpClass() method of each class file.
This set up is producing results that you have not intended. I think you are slightly misunderstanding what "best practice is to keep login test part out of whole test" means here.
This does not mean you need to write two separate tests -- one that logs in, and one that tests the rest of the functionality. This is actually bad practice, because you want your test cases to run independently of one another -- test cases should not rely on previous test cases to execute properly.
I think the solution you are looking for here is to write the login functionality into your setUp() method so that login is always performed before a test case starts.
This approach will prevent you from having the login part in with the test -- that's the original goal you mentioned here.
You can adjust your classes by removing the duplicate setUp() method, and inheriting LoginTest into your LegalPersonSearchTest so that you are only setting up once:
from utils.utils import * from selenium import webdriver from locators.locators import Locators from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import unittest from pages.loginPage import LoginPage # this is our "base" class class LoginTest(unittest.TestCase): driver = None # driver instance that we will inherit into LegalPersonSearchTest # initialize driver, go to testing URL, etc. def setUp(cls): cls.driver = webdriver.Firefox() cls.driver.implicitly_wait(10) cls.driver.maximize_window() cls.driver.get(URL) # call login here to login before test login_page = LoginPage(cls.driver) login_page .fill_login_form(adminUsername, adminPassword) login_page .click_login_button() # move teardown into same class as setUp() def tearDown(cls): cls.driver.quit()
We have declared a class variable for driver that you can pass into LegalPersonSearchTest. We have also removed the __main__ call, because the only entry point we need is the test_ method in LegalPersonSearchTest:
from selenium import webdriver import unittest from pages.legalPersonSearchPage import LegalPersonSearchPage from login_test import LoginTest # unsure of file name containing LoginTest class class LegalPersonSearchTest(LoginTest): # inherit LoginTest here so we can use driver def test_valid_organization_search(self): legal_page = LegalPersonSearchPage(self.driver) legal_page .open_legal_person_search_page() if __name__ == '__main__': unittest.main()
We have changed a few things here:
- Entry point for main method designated by
__main__ -- we only need this in one place, on the test case level (LegalPersonSearchTest) - Removed duplicate
setUp() method calls that were resulting in multiple driver instances getting created (mentioned in your problem description) - Created single class instance of driver in
LoginTest class to be passed into LegalPersonSearchTest class - Modified
setUp() method on LoginTest to initialize the driver and login -- so that you do not have to include login code for any test!
Update: Changes made following comments:
- Removed
login method from LoginTest class and moved login code under setUp() -- this will get performed before every test case now - Modified
test_valid_organization_search to use self.driver instead of driver when initializing PageObject
I've made many of these changes based on this sample Python test architecture that I pushed to my GitHub. The files I used as templates were base_test_fixture.py (for your LoginTest), and test_web_driver.py for your LegalPersonSearchTest.
You may notice that base_test_fixture.py also contains def _testInitialize() and def _testCleanup() -- these are methods that you can override in your LegalPersonSearchTest class to perform additional steps to be run before your test_ method. The idea here is that if you have multiple .py files containing test cases, but each .py file requires slightly different setup, and you need to do more than just setUp() method calls for. You can override the testInitialize() and testCleanup() methods in the test case class, and these methods will execute after setUp() and before the actual test_ method.
Let me know if you have any questions about this -- it's quite a bit to explain, but once you learn this architecture, you have a very powerful way of organizing and executing your test cases.