Getting fixture not found in pytest - python

I am getting following error while running pytest using following code im unable to figure out whats wrong please find below code snippets.
Console ouput :
================================================= test session starts =================================================
platform win32 -- Python 3.7.2, pytest-4.2.0, py-1.7.0, pluggy-0.8.1
rootdir: D:\Workspace\AutomationProject, inifile:
plugins: cov-2.6.1, allure-pytest-2.5.5
collected 1 item
tests\pages\test.py E [100%]
======================================================= ERRORS ========================================================
__________________________________________ ERROR at setup of test.test_test ___________________________________________
file D:\Workspace\AutomationProject\tests\pages\test.py, line 5
def test_test(self):
E fixture 'web_driver' not found
> available fixtures: _UnitTestCase__pytest_class_setup, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, monkeypatch, no_cover, pytestconfig, record_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
D:\Workspace\AutomationProject\tests\pages\test.py:5
=============================================== 1 error in 0.12 seconds ===============================================
My Base class contains following code:
from selenium import webdriver
import pytest
import unittest
#pytest.fixture(scope="class")
def web_driver(request):
driver = webdriver.Chrome("C:/chromedriver.exe")
request.cls.driver = driver
yield
web_driver.close()
#pytest.mark.usefixtures("web_driver")
class Base(unittest.TestCase):
'''
This fixture contains the set up and tear down code for each test.
'''
pass
and test class contains following code:
from core.web.Base import Base
class test(Base):
def test_test(self):
self.driver.get("http://google.com")
The test fixture is web_driver still getting error not found !

web_driver() is defined outside Base class scope, so it's invisible to the usefixtures as it is part of test class scope. You could move it to conftest file, but IMHO a better solution is to move web_driver inside Base
#pytest.mark.usefixtures("web_driver")
class Base(unittest.TestCase):
#pytest.fixture(scope="class")
def web_driver(self, request):
driver = webdriver.Chrome("C:/chromedriver.exe")
request.cls.driver = driver
yield
driver.close()
As a side note, it should be driver.close(), not web_driver.close()

Related

While executing script writing in python with selenium in pytest getting the message as 0 item collected and no test ran

this is the confest.py file present in the test cases file
import pytest
from selenium import webdriver
#pytest.fixture()
def setup():
driver = webdriver.Chrome()
return driver
this is login file present in the page package
import pytest
from selenium import webdriver
class Loginchatbot():
username_xpath = '//input[#id="username"]'
password_xpath = '//input[#id="password"]'
login_xpath = '//span[contains(text(),"Log in")]'
def __init__(self,driver):
self.driver = driver
def set_username(self,username):
#launching the browser
#login in the application
self.wait.driver.find_element_by_xpath(self.username_xpath).clear()
self.wait.driver.find_element_by_xpath(self.username_xpath).click().send_keys(username)
def set_password(self, password):
# launching the browser
# login in the application
self.wait.driver.find_element_by_xpath(self.password_xpath).clear()
self.wait.driver.find_element_by_xpath(self.password_xpath).click().send_keys(password)
def clicklogin(self):
# launching the browser
# login in the application
self.wait.driver.find_element_by_xpath(self.login_xpath).click()
this is the test_login file present in the test cases folder
import pytest
from selenium import webdriver
from p username = "shubhamgupta191190#gmail.com"ages.login import Loginchatbot
class test001_login:
baseurl = "https://teacher-learning-test.ef.com/"
password = "freeBugs!"
def test_login1(self,setup):
self.driver = setup
self.driver.get(self.baseurl)
self.lp = Loginchatbot(self.driver)
self.lp.set_username(self.username)
self.lp.set_password(self.password)
self.lp.clicklogin()
I am trying to design automation framework and I am new to selenium and I am using python with selenium and pytest and while executing the above script written in test_login and function name as test_login1 getting the error message as
platform win32 -- Python 3.11.0, pytest-7.2.0, pluggy-1.0.0
rootdir: C:\\Users\\GREEN EARTH\\PycharmProjects\\Chatbot
collected 0 items
================================================================ no tests ran in 0.01s \
Option 1. Change class name
Your test class is called test001_login.
pytest by default allows class names that start with Test.
Consider renaming your test class to Test001Login.
Source
Option 2. Change pytest naming convention
If you want to stick with test001_login class name and change the standard naming convention then you need to define it in your pytest.ini file like this:
[pytest]
python_classes = test
Source

Using a class-based test as a fixture

I am using this class which creates my login test:
import pytest
from pages.loginPage import LoginPage
from utils import utilis as utils
#pytest.mark.usefixtures("test_setup")
class TestLogin():
def test_login(self):
driver=self.driver
driver.get(utils.URL)
login =LoginPage(driver)
login.enterUsername(utils.USERNAME)
login.enterPassword(utils.PASSWORD)
login.clickLogin()
I want to re-use this test as a fixture for other tests, like this:
import pytest
from pages.loginPage import LoginPage
from pages.homePage import HomePage
from utils import utilis as util
#pytest.mark.usefixtures("test_login")
class TestAddRegulation():
def test_addRegulation(self):
driver = self.driver
homepage = HomePage(driver)
homepage.clickRegulationTile()
homepage.clickAddRegulationListItem()
And this is the conftest.py file with the test_setup fixture:
from selenium import webdriver
import pytest
def pytest_addoption(parser):
parser.addoption("--browser", action="store",
default="chrome",
help="Type in browser name e.g.chrome OR firefox")
#pytest.fixture(scope="class")
def test_setup(request):
browser = request.config.getoption("--browser")
if browser == 'chrome':
driver = webdriver.Chrome(executable_path=
r"C:/Users/user/PycharmProjects/RCM_AutomationFramework/drivers/chromedriver.exe")
elif browser == 'firefox':
driver = webdriver.Firefox(executable_path=
r"C:/Users/user/PycharmProjects/RCM_AutomationFramework/drivers/geckodriver.exe")
driver.implicitly_wait(5)
driver.maximize_window()
request.cls.driver = driver
yield
driver.close()
driver.quit()
print("Test is finished")
I can't get this to work, even if the test_login case is executed before the test_addRegulation test case.
I tried marking test_login as a fixture but it doesn't work. I can make it work if I dropped using classes.
Can I make a class method a fixture that is re-usable for other test classes?
Fixtures can be methods defined in a class, but then they are not available outside of the class. As the pytest documentation on fixtures states:
Fixture availability is determined from the perspective of the test. A fixture is only available for tests to request if they are in the scope that fixture is defined in. If a fixture is defined inside a class, it can only be requested by tests inside that class.
(Bold emphasis mine).
This means that you have to use a plain function to define re-usable fixtures. You can still access the class used by each test, however, via the request.cls attribute. Make sure to have the fixture take both the request and the test_setup scopes:
#pytest.fixture(scope="class")
def login(request, test_setup):
driver = request.cls.driver
driver.get(utils.URL)
login = LoginPage(driver)
login.enterUsername(utils.USERNAME)
login.enterPassword(utils.PASSWORD)
login.clickLogin()
Just put that fixture in your conftest.py file. You can use a different scope, provided it doesn't exceed the class scope of the test_setup fixture (so your choices are class and function here).
You can then use that fixture with no actual test body to test the login:
#pytest.mark.usefixtures("login")
class TestLogin:
def test_login(self):
# test passes if the login fixture completes.
pass
This does seem a bit redundant, of course.
Use the fixture for other classes the same way:
#pytest.mark.usefixtures("login")
class TestAddRegulation:
def test_addRegulation(self):
# ... etc.
A quick demo (without selenium, just plain Python):
import pytest
#pytest.fixture(scope="class")
def test_setup(request):
request.cls.fixtures = ["test_setup"]
yield
print("Test is finished, fixtures used:", request.cls.fixtures)
#pytest.fixture(scope="class")
def login(request, test_setup):
# The fixtures list was created by the test_setup fixture
fixtures = request.cls.fixtures
fixtures.append("login")
#pytest.mark.usefixtures("login")
class TestLogin:
def test_login(self):
assert self.fixtures == ["test_setup", "login"]
#pytest.mark.usefixtures("login")
class TestAddRegulation:
def test_addRegulation(self):
assert self.fixtures == ["test_setup", "login"]
Running these tests with pytest -vs (verbose mode, disabling stdout capture) produces:
...::TestLogin::test_login PASSEDTest is finished, fixtures used: ['test_setup', 'login']
...::TestAddRegulation::test_addRegulation PASSEDTest is finished, fixtures used: ['test_setup', 'login']

Use Session Scoped Fixture as Variable

I am writing tests in pytest and am using fixtures as variables.
Originally, this is how the fixtures looked:
#pytest.fixture(scope="class")
def user(request):
u = "Matt"
request.cls.u = u
return u
And then, there was another fixture to delete the user from the database once I finished with it.
In the tests, I used both fixtures like so #pytest.mark.usefixtures("user", "teardown fixture")
The teardown fixture was class scoped, until I decided to change it to session scoped, since I want to delete the user only after running all the tests.
The problem was that suddenly the teardown fixture couldn't access user, since user is class scoped.
I changed the user to session scoped, however, I am not sure how to access, or export it now.
#pytest.fixture(scope="session")
def user(request):
u = "Matt"
# request.cls.user = u -> WHAT GOES HERE INSTEAD OF THIS?
return u
User is no longer recognized in the test functions. The test is located inside of a class. The current function is something like this:
Class TestUser(OtherClassWhichInheritsFromBaseCase):
def test_user1(self, user1):
self.open("www.google.com")
print(user1)
When I try to run the code in pycharm I get the following error:
def _callTestMethod(self, method):
> method()
E TypeError: TestUser.test_user1() missing 1 required positional argument: 'user1'
Any advice?
I think you're approaching this from the wrong direction. If you need to clean up a fixture, you don't write a second fixture; you write your fixture as a context manager.
For example, you might write:
#pytest.fixture(scope="session")
def user():
u = User(name="Matt")
yield u
# cleanup goes here
And in your test code:
def test_something(user):
assert user.name == "Matt"
Here's a complete example. We start with this dummy user.py, which simply creates files to demonstrate which methods were called:
from dataclasses import dataclass
#dataclass
class User:
name: str
def commit(self):
open("commit_was_called", "w")
def delete(self):
open("delete_was_called", "w")
Then here's our test:
import pytest
import user
#pytest.fixture(scope="session")
def a_user():
u = user.User(name="testuser")
u.commit()
yield u
u.delete()
class TestUserStuff:
def test_user(self, a_user):
assert a_user.name == "testuser"
We run it like this:
$ pytest
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.10.1, pytest-6.2.4, py-1.11.0, pluggy-0.13.1
rootdir: /home/lars/tmp/python
plugins: testinfra-6.5.0
collected 1 item
test_user.py . [100%]
================================================================================================ 1 passed in 0.00s ================================================================================================
After which we can confirm that both the commit and delete methods were called:
$ ls
commit_was_called
delete_was_called
test_user.py
user.py

Testing class methods with pytest - error - fixture 'self' not found

I want to test a class method with py.test and I've followed this post Testing class methods with pytest.
I've got a file with my method (calgo.py) and another file with my test (test_calgo.py), and both files are in the same folder (learning_ut).
When I run pytest I get an error message saying fixture 'self' not found.
Where am I going wrong?
Thanks!
# calgo.py
class MyClass():
def func(self, x):
return x+1
# test_calgo.py
import calgo
def test_func(self):
mc = MyClass()
assert mc.func(3) == 4
# Command line
(pyenv) C:\Users\Jimmy\Desktop\learning_ut>pytest
# Error message
(pyenv) C:\Users\Jimmy\Desktop\learning_ut>pytest
================================================= test session starts =================================================
platform win32 -- Python 3.6.13, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: C:\Users\Jimmy\Desktop\learning_ut
collected 1 item
test_calgo.py E [100%]
======================================================= ERRORS ========================================================
_____________________________________________ ERROR at setup of test_func _____________________________________________
file C:\Users\Jimmy\Desktop\learning_ut\test_calgo.py, line 11
def test_func(self):
E fixture 'self' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary,
doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property,
record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
C:\Users\Jimmy\Desktop\learning_ut\test_calgo.py:11
=============================================== short test summary info ===============================================
ERROR test_calgo.py::test_func
I don't know about pytest, in unittest you create a test class, which would have method belonging to this class and have self as parameter. However, your error seems to be causes by the function in calgo.py, which does not belong to a class, thus does not have the self reference. Try the following:
import calgo
def test_func():
mc = MyClass()
assert mc.func(3) == 4

How to call a 'debug' method in py.test in case of an failure?

I am trying to write a py.test test with selenium to test a complex website. Because the setup is complex, the test can fail even before the actual test. But in such a case I want to be able to call a 'debug' function (maybe its a teardown function which I can use to debug things.
Example:
The test uses a fixture which returns a selenium webdriver
def test1(driver):
driver.get("my page")
...
other tests, login, etc etc
But now the call driver.get fails because of any reason. But in such a case I want to be able to investigate things like
def debug(driver):
driver.screenshot(...)
print(driver.page_source)
...
driver.quit()
(including the shutdown of the driver, as the browser would stay open) with the same driver instance as has been used in the test method.
Is there a way to do that?
The trickiest part is to pass the test result into the fixture, the rest is pretty much trivial. Following the pytests example Making test result information available in fixtures, add a custom hook in your conftest.py:
import pytest
#pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
setattr(item, "rep_" + rep.when, rep)
return rep
Now you can enhance your driver fixture with custom teardown logic in case the test fails:
# test_selenium.py
import pytest
from selenium import webdriver
def debug(driver):
print('debug: ', driver.title)
#pytest.fixture
def driver(request):
driver = webdriver.Firefox()
yield driver
if request.node.rep_setup.passed and request.node.rep_call.failed:
# this is the teardown code executed on test failure only
debug(driver)
# this is the teardown code that is always executed
driver.quit()
def test_fail(driver):
driver.get('http://wtf')
def test_ok(driver):
driver.get('https://www.google.de')
Running the tests yields:
$ pytest -sv
=============================== test session starts ===============================
platform darwin -- Python 3.6.3, ...
cachedir: .cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-48521762, inifile:
plugins: ...
collecting ... collected 2 items
test_spam.py::test_fail FAILED [ 50%]
debug Server Not Found
test_spam.py::test_ok PASSED [100%]
==================================== FAILURES =====================================
____________________________________ test_fail ____________________________________
driver = <selenium.webdriver.firefox.webdriver.WebDriver( ...
...
------------------------------- Captured log setup --------------------------------
remote_connection.py 474 DEBUG POST http://127.0.0.1:50319/session { ...
...
remote_connection.py 561 DEBUG Finished Request
======================== 1 failed, 1 passed in 7.23 seconds =======================

Categories