How to pass a parameter to a class scope fixture - python

Lets say I have a fixture like this:
#pytest.fixture(scope="class")
def some_fixture(some_paramaters):
do_something
yield
do_something
And i want to use it in this way:
#pytest.mark.usefixtures('some_fixtures')
class TestSomething:
code....
Is it possible to pass the parameter some_paramter using #pytest.mark.usefixtures decorator. Or is there any way to pass that parameter?

You could use something like this by using an autouse fixture.
import pytest
import requests
#pytest.fixture(scope="class")
def some_fixture(some_parameters):
do_something
yield
do_something
class TestSomething:
#pytest.fixture(autouse=True)
def _calling_method(self, some_fixture):
self._response = some_fixture(some_parameters)

Related

Python unit test with mocking assert_called for function outside class

I am trying to test whether a function defined outside of a class is called by a class method.
def function_a(input):
return input
class MyClass:
def __init__(self, user_function=function_a):
self.user_function = user_function
def function_b(input):
return self.user_function(input)
I am trying to test the function call like this:
from unittest import TestCase
from unittest.mock import Mock
class TestMyClass(TestCase):
def test_function_call(self):
my_class = MyClass(user_function=function_a)
mock = Mock()
my_class.function_b(input)
mock.function_a.assert_called()
This gives me
AssertionError: Expected 'function_a' to have been called.
I am using Python 3.6. Looking at the output I can see that function_a was called. What am I doing wrong?
This here did the trick:
from unittest import TestCase
from unittest.mock import MagicMock
class TestMyClass(TestCase):
def test_function_call(self):
my_class = MyClass(user_function=MagicMock())
my_class.function_b(input)
my_class.user_function.assert_called()

Is it discouraged to import conftest.py within test-modules?

I am creating an object within conftest.py and use it in some fixtures. I also need to use this object within my test-modules. Currently I am importing conftest.py inside my test-modules and make use of that 'helper' object. I am pretty sure that this is not the recommended way. I am looking forward to your suggestions.
Thank you :)
Following is the dummy-coded version of my question:
conftest.py
import pytest
class Helper():
def __init__(self, img_path:str):
self.img_path = img_path
def grayscale(self):
pass
def foo(self):
pass
helper = Helper("sample.png")
#pytest.fixture()
def sample():
return helper.grayscale()
test_module.py
import conftest
helper = conftest.helper
def test_method1(sample):
helper.foo()
...
As already commented, I also handled such scenarios by fixtures before if I have a helper class in tests.
conftest.py
import pytest
class Helper():
def __init__(self, img_path: str):
self.img_path = img_path
def grayscale(self):
pass
def foo(self):
pass
#pytest.fixture(scope="session")
def helper():
return Helper("sample.png")
#pytest.fixture()
def sample(helper):
return helper.grayscale()
test_module.py
def test_method1(helper, sample):
helper.foo()

Mock a decorator function to bypass decorator logic

I'm trying write some unittests for my code which in turn uses a decorator
import unittest
from unittest.mock import patch
from functools import wraps
def decorator(f):
#wraps(f)
def decorated(x):
return f(x+1)
return decorated
#decorator
def get_value(x):
return x
class MyTestCase(unittest.TestCase):
#patch('file.decorator', lambda f: f)
def test_something(self):
result = get_value(1)
self.assertEqual(1, result)
I'm trying to mock the decorated function to just return f and completely bypass the decorator logic part. This is talked about in Overriding decorator during unit test in python but doesn't really work.
Since the decorator runs immediately after you define get_value, it's too late to mock the decorator. What you can do, though, (since you used functools.wraps) is mock get_value itself and use get_value.__wrapped__ (the original function) in some way. Something like
#patch('tmp.get_value', get_value.__wrapped__)
def test_something(self):
result = get_value(1)
self.assertEqual(1, result)
(In this case, I put your original code, with the above change, in tmp.py, and ran it as python3 -munittest tmp.py, hence my patching of the reference tmp.get_value.)
If you anticipate the need to test the undecorated original, though, it might be simpler to keep it under its own (private) name to test: no patching needed.
import unittest
from functools import wraps
def decorator(f):
#wraps(f)
def decorated(x):
return f(x+1)
return decorated
def _get_value(x):
return x
get_value = decorator(_get_value)
class MyTestCase(unittest.TestCase):
def test_something(self):
result = _get_value(1)
self.assertEqual(1, result)

using the pytest.fixture scope function on setup_class

I have two test case modules TestClassA, TestClassB. On test_1_that_needs_resource_a in TeseClass A, I am using fixture so I can call resource_a and pass parameters before executing testcase. How can I use the same fixture on setup_class in TestClassB so all testcase
in TestClassB so the fixture can be called one time before all testcase in TestClassB
import pytest
#pytest.fixture(scope='function')
def resource(request):
print('resources_a_setup()')
return request.param
class TestClassA:
#classmethod
def setup_class(cls):
print('\nsetup_class()')
#classmethod
def teardown_class(cls):
print('\nteardown_class()')
#pytest.mark.parametrize('resource', [dict(), dict(name=1)], indirect=['resource'])
def test_1_that_needs_resource_a(self, resource):
assert resource == dict()
print(f'\ntest_1_that_needs_resource_a(), {resource}')
class TestClassB:
## I would like to call resource fixture with passing some parameter on setup_class here
#classmethod
def setup_class(cls):
print('\nsetup_class()')
#classmethod
def teardown_class(cls):
print('\nteardown_class()')
def test_1_that_needs_resource_a(self):
print('\ntest_1_that_needs_resource_a()')

tmpdir in py.test setup_class

I use py.test for testing.
In setup_class() I need to use tmpdir for my class constructor:
class TestMyClass:
def setup_class(self):
self.t = MyClass(path=tmpdir)
def test_test(self):
assert True
And I have an error:
NameError: name 'tmpdir' is not defined
I can't use setup_class(self, tmpdir).
If I use this code:
def test_needsfiles(tmpdir):
print(tmpdir)
assert 0
It's work, but I need tmpdir in my class constructor.
How to do this?
Thanks!
UPD
I try to do this:
#pytest.yield_fixture()
def constructor(tmpdir):
_t = MyClass(path=str(tmpdir))
yield _t
class TestMyClass:
def test_test(self, constructor):
pass
But I can't use scopes in fixture:
ScopeMismatch: You tried to access the 'function' scoped fixture 'tmpdir' with a 'module' scoped request object, involved factories
I do this:
class TestMyClass:
#pytest.fixture(autouse=True)
def setup(self, tmpdir):
self.tmpdir = tmpdir.strpath
If you don't want to use #pytest.fixture(autouse=True) as #santon suggested, but you want to create a fixture outside TestMyClass (like you write in the UPD part), you can try this:
#pytest.fixture
def t(tmpdir):
return MyClass(tmpdir)
class TestMyClass:
def test_test(self, t):
assert True
If you don't want to return anything in a fixture, but for example go to a temp directory, you can also do:
#pytest.fixture
def t(tmpdir):
os.chdir(str(tmpdir))
#pytest.mark.usefixtures("t")
class TestMyClass:
def test_test(self):
assert True
You can use tempfile module to handle with temporary files and dirs. In setup you can create temp dir with mkdtemp and delete it at tearDown from test class.
import shutil, tempfile
import unittest
class TestMyClass(unittest.TestCase):
def setUp(self):
self.tmp_dir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.tmp_dir)

Categories

Resources