NameError: name 'mocker' is not defined using pytest - pytest

I'm learning to use mock when testing with pytest.
I got a simple test function:
import pytest
import smtplib
def test_send_email():
with mocker.patch('smtplib.SMTP') as mock:
assert True
But when I try to run this test I got the following error: NameError: name 'mocker' is not defined.
I already verified that mock, pytest and pytest-mock are correctly installed.
What am I doing wrong ?

Welll. was a stupide error... I was missing the mocker parameter...
It should be:
def test_send_email(mocker):
with mocker.patch('smtplib.SMTP') as mock:
assert True

Related

How to pass extra argument to python unittest?

I want to pass library location while running unittest command. As I have to import library for using. Suppose the library name is some_lib . Same library will be executed on Linux as well as Windows.
Using python version 3.7.11
Used command : python3 -m unittest test_file.py lib_location
Details of test file.
import sys
sys.path.append(sys.argv[1]) # Hard code of path works fine.
import some_lib
import unittest
class TestCasesForSerializePy(unittest.TestCase):
#classmethod
def setUpClass(self):
self.archive_handler = some_lib.open('./test.archive')
def test_existing_archive(self):
self.assertTrue(self.archive_handler.isOpen())
if __name__ == '__main__':
# unittest.main(argv = [sys.argv[0]])
# sys.argv.pop()
unittest.main()
Error: ModuleNotFoundError: No module named 'C:/REC_158/build/lib'
Tried different approach as available on google.
Approach 1:
sys.argv.pop()
unittest.main()
Approach 2:
del sys.argv[1:]
unittest.main()
Approach 3:
unittest.main(argv=[sys.argv[0]]

Pytest skipping a test class that inherits from a builtin

TLTR:
The question is maximally easy: Please look at the code base case. Pytest just ignoring this class. How I should run tests on a such class?
I just started switching from a simple python tests (with just assert) to testing with pytest and come across with this problem. Most of my tests is are classes that extending a real classes with test methods. One of my classes inherit from collections.UserDict. Pytest just ignoring this class. How I should run tests on a such class?
# Inheritance from object are ok, Inheritance from dict are not ok. Need dict :(
class TestFoo(dict):
def test_foo(self):
assert 1
output:
/home/david/PycharmProjects/proj/venv/bin/python /snap/pycharm-professional/302/plugins/python/helpers/pydev/pydevd.py --multiprocess --qt-support=auto --client 127.0.0.1 --port 44145 --file /snap/pycharm-professional/302/plugins/python/helpers/pycharm/_jb_pytest_runner.py --path /home/david/PycharmProjects/proj/tests/unit_tests_2.py
Testing started at 11:07 ...
Launching pytest with arguments /home/david/PycharmProjects/proj/tests/unit_tests_2.py --no-header --no-summary -q in /home/david/PycharmProjects/proj/tests
============================= test session starts ==============================
collecting ... collected 0 items
============================= 2 warnings in 0.03s ==============================
Process finished with exit code 5
Empty suite
UPD Thanks for #Teejay Bruno, running tests from pycharm hiding a warning from me:
PytestCollectionWarning: cannot collect test class 'TestFoo' because it has a __init__ constructor
The warning tells you the problem:
PytestCollectionWarning: cannot collect test class 'TestFoo' because it has a __init__ constructor
If I understand what you're trying to do, why not just pass the object as a fixture?
import pytest
#pytest.fixture
def my_dict():
return dict()
class TestFoo:
def test_foo(self, my_dict):
assert len(my_dict) == 0

What does it mean when pytest fixture yields from another fixture instance?

This is the real code from MLflow: https://github.com/mlflow/mlflow/blob/8a7659ee961c2a0d3a2f14c67140493a76d1e51d/tests/conftest.py#L42
#pytest.fixture
def test_mode_on():
try:
prev_env_var_value = os.environ.pop(_AUTOLOGGING_TEST_MODE_ENV_VAR, None)
os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR] = "true"
assert is_testing()
yield
finally:
if prev_env_var_value:
os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR] = prev_env_var_value
else:
del os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR]
#pytest.fixture(autouse=True, scope="session")
def enable_test_mode_by_default_for_autologging_integrations():
"""
Run all MLflow tests in autologging test mode, ensuring that errors in autologging patch code
are raised and detected. For more information about autologging test mode, see the docstring
for :py:func:`mlflow.utils.autologging_utils._is_testing()`.
"""
yield from test_mode_on()
There are also multiple places where test_mode_on is used like this:
#pytest.mark.usefixtures(test_mode_on.__name__)
def test_safe_patch_propagates_exceptions_raised_outside_of_original_function_in_test_mode(
When I try to run any tests I get the following:
tests/test_version.py::test_is_release_version ERROR [100%]
==================================== ERRORS ====================================
Fixture "test_mode_on" called directly. Fixtures are not meant to be called directly,
but are created automatically when test functions request them as parameters.
See https://docs.pytest.org/en/stable/fixture.html for more information about fixtures, and
https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code.
I want to understand what the original code was doing with yield from test_mode_on() and how to fix it.
Update:
I've tried to change the code to request the fixture, but got an error that test_mode_on has function scope while enable_test_mode_by_default_for_autologging_integrations has session scope.
#pytest.fixture(autouse=True, scope="session")
def enable_test_mode_by_default_for_autologging_integrations(test_mode_on):
"""
Run all MLflow tests in autologging test mode, ensuring that errors in autologging patch code
are raised and detected. For more information about autologging test mode, see the docstring
for :py:func:`mlflow.utils.autologging_utils._is_testing()`.
"""
yield from test_mode_on()
The intention obviously was to re-use a function-scoped fixture in a session-scoped fixture. Apparently, this was an option that was working in old pytest versions.
In any recent pytest version, this is not possible (as you have noticed). If you cannot fix the MLflow tests, your only option is to use an old pytest version that still supports that - MLflow has pinned pytest to 3.2.1 (probably for that same reason).
Be aware that any pytest plugin you have installed will likely not work with that pytest version either, so you have to downgrade or remove the plugins, too.
This recent issue is probably related to the outdated pytest version, so there is a chance that this will be addressed in MLflow.
UPDATE:
Just realized that it would help to show how to fix this for a current pytest version. In current pytest you are not allowed to derive (or yield) from a fixture with a narrower scope, as this would often not work as expected. You can, however, move the fixture code into a generator function, and yield from that. So a working version could be something like:
def test_mode_on_gen():
try:
prev_env_var_value = os.environ.pop(_AUTOLOGGING_TEST_MODE_ENV_VAR, None)
os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR] = "true"
assert is_testing()
yield
finally:
if prev_env_var_value:
os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR] = prev_env_var_value
else:
del os.environ[_AUTOLOGGING_TEST_MODE_ENV_VAR]
#pytest.fixture
def test_mode_on():
yield from test_mode_on_gen()
#pytest.fixture(autouse=True, scope="session")
def enable_test_mode_by_default_for_autologging_integrations():
yield from test_mode_on_gen()

pytest not discovering test in pyDev

I'm trying to build and run (selenium which is not relevant) test-suite with pytest framework.
I wrote a simple test as follows
class test_pqr():
def test_lmn(self):
print("AAAAAAAAAAAAAAAAAAAAA")
assert True
def test_xyz(self):
assert False
x= test_pqr()
x.test_lmn()
when I run it I got result...
if I run xyz as well... eg
class test_pqr():
def test_lmn(self):
print("AAAAAAAAAAAAAAAAAAAAA")
assert True
def test_xyz(self):
assert False
x= test_pqr()
x.test_lmn()
x.test_xyz()
get results as...
what dose
imported unittest before running pytest.main
error means?
why can't it discover test?
collected 0 items
why are methods run only when there is error?
After a long search and trial and error found the culprit.
You should name class Test_*..
T in UPPER CASE for Class
t in lower case for methods...
though tests are running as supposed, the error remains...

How to pass config as command line argument in Pytest which is not used as test input

Want to know how do I read the command line argument for "Pytest" to get the input and use the variable not as test input with fixture but a parameter to do some other operation.
Here is what I am trying to achieve :
pytest --folder=< label > test_my_logic.py
where label can be a, b and c.and based on the label value I will get the actual 'folder' path which has expected data. e.g.
label=a, folder=common/test_data/a
label=b, folder=common/test_data/b
I have added the conftest.py as below:
import pytest
def pytest_addoption(parser):
parser.addoption("--folder", action="store", default="All",
help="Please enter the folder which needs to be executed")
#pytest.fixture
def folder(request):
return request.config.getoption("--folder")
I have a json and util method using which I can read the json to get the value of actual folder value of a,b etc. I am seeking help to know in my script how do I get the argument --folder and use it to do other operation instead of passing it to the test method with fixture in my script ? In my test script where I am reading various global variables , I have :
test_my_logic.py
import pytest
import json
import sys
sys.path.append(os.path.realpath("%s/../../../../../common/utils" % os.path.dirname(os.path.abspath(__file__))))
import utils
print folder
TEST_ATTRIB = utils.getTestAttributes()['LOL']
PLACE_REQUEST_URL = utils.getURLs()['IMO']
...
...
In command line:
py.test --folder=a tests/test_my_logic.py
Error returned:
tests/test_my_logic.py:16: in <module>
print folder
E NameError: name 'folder' is not defined
Thanks in Advance !
folder is a fixture, it should be used as a parameter for test:
def test_a(folder):
print folder