Fixture not found pytest - python-3.x

Hey I got a simple test where the fixure is not found. I am writting in vsc and using windows cmd to run pytest.
def test_graph_add_node(test_graph):
E fixture 'test_graph' 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.
This is the error I get, here is the test code:
import pytest
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'giddeon1.settings')
import django
django.setup()
from graphs.models import Graph, Node, Tag
#pytest.fixture
def test_graph():
graph = Graph.objects.get(pk='74921f18-ed5f-4759-9f0c-699a51af4307')
return graph
def test_graph():
new_graph = Graph()
assert new_graph
def test_graph_add_node(test_graph):
assert test_graph.name == 'Test1'
im using python 3.9.2, pytest 6.2.5.
I have see some similar questions but they all handle wider or bigger problems.

You appear to be defining test_graph twice, which means that the second definition will overwrite the first. And you added #pytest.fixture to a test_ method when you used it, but #pytest.fixture should be added to non test methods so that tests can use that fixture. Here's how the code should probably look:
import pytest
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'giddeon1.settings')
import django
django.setup()
from graphs.models import Graph, Node, Tag
#pytest.fixture
def graph():
graph = Graph.objects.get(pk='74921f18-ed5f-4759-9f0c-699a51af4307')
return graph
def test_graph():
new_graph = Graph()
assert new_graph
def test_graph_add_node(graph):
assert graph.name == 'Test1'
Above, the first method has been renamed to graph so that the next method doesn't override it (and now #pytest.fixture is applied to a non-test method). Then, the 3rd method uses the graph fixture. Make any other changes as needed.

Related

Starting a Flask Server from Within Test Code?

I'm working through the Flasky tutorial from Miguel Grinberg's book Flask Web Development 2e and I've run into a snag with the end-to-end testing in Chapter 15. When I try to run the code I get a console message
* Ignoring a call to 'app.run()' that would block the current 'flask' CLI command.
Only call 'app.run()' in an 'if __name__ == "__main__"' guard.
followed by the browser reporting "Firefox cannot establish a connection..." This suggest to me that the test server is not starting.
Here's the code, from pages 231-233 of the book (the file is tests/test_selenium.py):
import threading
import unittest
from selenium import webdriver
from app import create_app, db, fake
from app.models import Role, User
class SeleniumTestCase(unittest.TestCase):
browser = None
#classmethod
def setUpClass(cls) -> None:
try:
cls.browser = webdriver.Firefox()
except Exception as e:
pass
if cls.browser:
cls.app = create_app('testing')
cls.app_context = cls.app.app_context()
cls.app_context.push()
import logging
logger = logging.getLogger('werkzeug')
logger.setLevel('ERROR')
db.create_all()
Role.insert_roles()
fake.users(10)
fake.posts(10)
admin_role = Role.query.filter_by(permissions=0xff).first()
admin = User(email='john#example.com', password='cat', username='john', role=admin_role, confirmed=True)
db.session.add(admin)
db.session.commit()
cls.server_thread = threading.Thread(
target=cls.app.run,
kwargs={
'debug': 'false',
'use_reloader': False,
'use_debugger': False,
'host': '0.0.0.0',
'port': 5000
}
)
cls.server_thread.start()
#classmethod
def tearDownClass(cls) -> None:
if cls.browser:
cls.browser.get('http://localhost:5000/shutdown')
cls.browser.quit()
cls.server_thread.join()
db.drop_all()
db.session.remove()
cls.app_context.pop()
def setUp(self) -> None:
if not self.browser:
self.skipTest('Web browser not available')
def tearDown(self) -> None:
pass
def test_admin_home_page(self):
self.browser.get('http://localhost:5000/') # fails here
self.assertRegex(self.browser.page_source, 'Hello,\s+Stranger!')
self.fail('Finish the test!')
How can I get a test server up and running from within the test code? (I putzed around with Flask-Testing for a few days before giving it up as unmaintained.)
ADDENDUM: Further experimentation has determined that the problem lies in the explicit call to app.run() conflicting with the Flask CLI's implicit call to app.run(), but without the explicit call the test server doesn't start.
I want to run this from the Flask CLI the same as my unit tests. This means I need to find a way to start the test server after the test database is populated, which happens after the test class's code begins to run. The CLI command code is:
#app.cli.command()
#click.argument('test_names', nargs=-1)
def test(coverage, test_names):
"""Run the unit tests"""
import unittest
if test_names:
tests = unittest.TestLoader().loadTestsFromNames(test_names)
else:
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
so running from __main__ would bypass the tests' load/run sequence.
I found a feasible solution using Timer
import unittest
from threading import Timer
Create two variables on top in your code
timer = None
myapp = None
class ApplicationTest(unittest.TestCase):
Now at the bottom of the file create main method and custom method of timer, I assume startTest as method name
In the main method you can call create_app and put it in global variable and use that myapp variable inside your selenium testing code
unittest.main() will manually trigger your test class and run the test cases one after one, unfortunately the test runs twice, I don't know why
def startTest():
timer.cancel()
unittest.main()
if __name__ == '__main__':
timer = Timer(6.0, startTest)
timer.start()
myapp = create_app()
myapp.run(debug=True, threaded=True)

Mocking a class in a Flask API

I have three files
helper.py
class helper:
def __init__(self, out_file):
self.out_file = out_file
def foo(first, second):
# Write data to file
flask_API.py
from helper import helper
#app.route('/', methods=['POST'])
def parse_request():
content = request.get_json()
out_file = #based on timestamp
helper(out_file).foo(content['first'], content['second'])
test_flask.py
import unittest
from unittest.mock import patch
import flask_API
class testFlaskAPI(unittest.TestCase):
def setUp(self):
self.app = flask_API.app.test_client()
self.app.test = True
#patch('flask_API.app.helper', return_value=None)
def test_service(self, mock_helper):
response = self.app.post(base_url, data=json.dumps({"some":"value"}, content_type='application/json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
I am having trouble mocking the helper class. This gives me an error saying
AttributeError: <Flask 'flask_API'> does not have the attribute 'helper'
I read that a class/method needs to be mocked where it is being called instead of where it's defined. Is there something wrong with the way I am patching the class?
In the end the solution turned out to be fairly simple. First there was no need to add app in the #patch decorator. The test just needed #patch('flask_API.helper'). Second, I first needed to return the mock of the class and then mock the function call as well. So the final answer turned out to be
#patch('flask_API.helper')
def test_service(self, mock_helper):
mocking_helper = mock_helper.return_value # mocking the class
mocking_helper.foo.return_value = None
response = self.app.post(base_url, data=json.dumps({"some":"value"}, content_type='application/json')
self.assertEqual(response.status_code, status.HTTP_200_OK)

AttributeError: 'ClassName' object has no attribute 'driver' on Appium Python

I am using this body(desired_caps are set properly in config file)
Whatever I do I receive 'AttributeError: 'ClassName' object has no attribute 'driver'' or similar errors - no find_element_by_xpath attribute or whatever.
Do you have any suggestions? I am doing in the same way as in lectures, maybe anything related to appium + python setups?
import unittest
from appium import webdriver
import time
import tracemalloc
tracemalloc.start()
from config import desired_caps
# self = webdriver
# self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
class BaseTest(unittest.TestCase):
def test_testcase1(self):
self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
def test_credentials(self):
email = self.driver.find_element_by_xpath("proper Xpath")
email.send_keys("Test")
save = self.driver.find_element_by_link_text("Log In")
save.click()
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(BaseTest)
unittest.TextTestRunner(verbosity=3).run(suite)
you need to make your driver in a function named setUp(). The unit test suite executes kinda like this.
setUp()
run test_testcase1()
tearDown()
setUp()
run test_credentials()
teardown()
...etc...
if driver driver is not made in setup() the other tests will not know about it. Unless you make driver in every single test. Same goes for any other test variables you'd need.
This way each test is independent of each other, and each test gets a fresh start.

Python - Mock class init that instantiates another class inside

I have the following python file board.py:
def __init__(self, language):
self.foo = Foo(language)
self.words = Aux(self.foo)
And I'm creating this test_file:
#classmethod
def setUpClass(cls):
super().setUpClass()
cls.board = Board('pt')
def test_total_time(self):
self.board.total_time(True)
#some assert
But I'm getting a FileNotFoundError because Aux.___init____() calls a self.foo.method() that opens a file and reads from it.
Is there a way to mock self.foo.method(), or the class Aux?
You will want to patch the module. If you give me the name of the test file and the class you are testing. I can finish this answer for you.
In the test file:
import unittest
def BoardTestCase(unittest.TestCase):
#classmethod
def setUpClass(cls):
super().setUpClass()
cls.aux_mock = unittest.mock.patch('file_undertest.Aux')
cls.board = Board('pt')
def test_total_time(self):
self.board.total_time(True)
#some assert
I would suggest using pytest instead of the standard library unittest. Your tests will be written as functions meaning you can reuse the Board class only when needed to. You can set more robust fixtures (Board class test cases) and the mocker extension is more intuitive if you spend the 15 minutes to wrap your head around it.

Pytest: no tests ran

I have the following class file and a corresponding test file
dir.py:
import os
class Dir:
def __init__(self, path=''):
self.path = path
#property
def path(self):
return self._path
#path.setter
def path(self, path):
abspath = os.path.abspath(path)
if abspath.exists():
self._path = path
else:
raise IOError(f'{path} does not exist')
and dir_test.py:
import unittest
from ..dir import Dir
class TestDir(unittest.TestCase):
def IOErrorIfPathNotExists(self):
with self.assertRaises(IOError):
Dir.path = "~/invalidpath/"
with self.assertRaises(IOError):
Dir('~/invalidpath/')
if __name__ == "__main__":
unittest.main()
but when I run
pytest -x dir_test.py
it just prints no tests ran in 0.01 seconds
and I have no idea why. It is my first time using pytest except with exercises from exercism.io, and I can't spot any difference to their test files.
I am running it in a virtual environment (Python 3.6.5), with pytest and pytest-cache installed via pip.
That's because your test method is not named properly.
By default, pytest will consider any class prefixed with Test as a test collection.
Yours is TestDir, this matches.
By default, pytest will consider any function prefixed with test as a test.
Yours is IOErrorIfPathNotExists, which does not start with test and is not executed.
Source.

Resources