I've been teaching myself test automation with Pytest and Selenium web driver. All my test functions were in a single file called test_web.py, which is in a directory named tests. I split all the functions up and placed them in their own files in a separate directory called TestCases. For example, this is what TestCase_AddStar.py looks like:
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class Tags:
starSysButton = '//li[button][1]'
addStarButton = "//button[contains(text(), 'Add Star')]"
starNameField = "//input[1]"
modalAddButton = f"(//button[contains(text(), 'Add')])[2]"
starPath = f"//td[contains(text(),'Bob')]"
modalClose = "//button[@class='btn-close']"
class TestCase_AddStar():
URL = 'http://localhost:4200'
def __init__(self, browser):
self.browser = browser
def load(self):
self.browser(self.URL)
def test_addStar(self, browser):
starElement = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.starSysButton)))
starElement.click()
newStarElement = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.addStarButton)))
newStarElement.click()
enterStarName = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.starNameField)))
enterStarName.send_keys("Bob")
clickAddButton = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.modalAddButton)))
clickAddButton.click()
WebDriverWait(browser, 5).until(EC.alert_is_present())
alert = Alert(browser)
alert.accept()
closeModal = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.modalClose)))
closeModal.click()
results = WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH, Tags.starPath)))
if results:
assert results
And this is what the driver, test_web.py. looks like now:
import pytest
from TestCases.TestCase_AddStar import TestCase_AddStar
from selenium.webdriver import Firefox
@pytest.fixture
def browser():
driver = Firefox()
driver.implicitly_wait(10)
yield driver
driver.quit()
def basic_test(browser):
add_star = TestCase_AddStar(browser)
add_star.load()
When I run the test, I get a collection warning:
PytestCollectionWarning: cannot collect test class 'TestCase_AddStar' because it has a init constructor (from: tests/test_web.py) class TestCase_AddStar():
I've tried adding the line "test = False" to the class TestCase_AddStar, I've tried renaming the file so that it doesn't have the word "test" in its filename, and I've tried to do away with the init constructor altogether. Nothing has worked. I either get a collection warning, the test is skipped outright, or the test times out because the browser doesn't load.
Does anyone have any advice?
Edit 1
TestCase_AddStar.py
class TestCase_AddStar():
URL = 'http://localhost:4200'
@pytest.fixture
def load_browser(self, browser):
browser(self.URL)
yield
def test_addStar(self, load_browser):
starElement = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.starSysButton)))
starElement.click()
newStarElement = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.addStarButton)))
newStarElement.click()
enterStarName = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.starNameField)))
enterStarName.send_keys("Bob")
clickAddButton = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.modalAddButton)))
clickAddButton.click()
WebDriverWait(load_browser, 5).until(EC.alert_is_present())
alert = Alert(load_browser)
alert.accept()
closeModal = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable((By.XPATH, Tags.modalClose)))
closeModal.click()
results = WebDriverWait(load_browser, 10).until(EC.presence_of_element_located((By.XPATH, Tags.starPath)))
if results:
assert results
test_web.py
import pytest
from TestCases.TestCase_AddStar import TestCase_AddStar
from selenium.webdriver import Firefox
@pytest.fixture
def browser():
driver = Firefox()
driver.implicitly_wait(10)
yield driver
driver.quit()
TestCase_AddStar()
I get the following error in traceback:
@pytest.fixture
def load_browser(self, browser):
browser(self.URL)
E TypeError: 'WebDriver' object is not callable
Edit 2
Added .get() as recommended below. But I've got a new error now.
CodePudding user response:
As you have noticed, a test cannot have an argument in __init__
because it is created by pytest
automatically. As far as I understand, you just want to load a specific URL in your specific test class - this is something that can be done in a fixture, too. Just derive the fixture from your browser
fixture and add the load function:
class TestCase_AddStar:
URL = 'http://localhost:4200'
@pytest.fixture
def load_browser(self, browser):
browser.get(self.URL)
yield browser
def test_addStar(self, load_browser):
...
Note that you don't need the __init__
method and the basic_test
function (which will not work with pytest
anyway). You can add a similar derived fixture into each test class with another URL parameter.
Your derived fixture will be equivalent to:
@pytest.fixture
def load_browser(self):
driver = Firefox()
driver.implicitly_wait(10)
driver.get(self.url)
yield driver
driver.quit()
(this is just for illustration how the derived fixture would work)