Passing parameters to pytest BOTH fixture and test - python-3.x

I'm using a python fixture browser_manager from a library which it would be inconvenient to modify or wrap in another class. browser_manager takes some variable some_config, which is passed to this fixture by indirect.
#pytest.fixture(name="browser_manager")
def _browser_manager(request)
indirect_params = getattr(request, "param", dict())
return BrowserManager(indirect_params)
#pytest.mark.parametrize(
"browser_manager",
[(some_config)],
indirect=["browser_manager"]
)
def test_browser_manager(browser_manager):
# some test goes here
My question is how can I access some_config in the test function itself? some_config is successfully passed to the fixture. I could simply pass some_config in twice, but I want to avoid that for maintainability. As mentioned before, it would be inconvenient to modify the fixture.
Thanks!

To answer was actually right above in my question. I made use of the fixture's request.
#pytest.fixture(name="browser_manager")
def _browser_manager(request)
indirect_params = getattr(request, "param", dict())
return BrowserManager(indirect_params)
#pytest.mark.parametrize(
"browser_manager",
[{"attribute": value}],
indirect=["browser_manager"]
)
def test_browser_manager(browser_manager):
attr_value = getattr(browser_manager.request, "param", dict()).get("attribute")

Related

Can I define a `setup_function` on Pytest that gets executed for every test case prior to any fixture disregarding its scope

Let's explain my question with an example:
import pytest
#pytest.fixture(scope="session", autouse=True)
def print_session():
print("session fixture")
yield
def setup_function(funtion):
print("function setup")
def test_printer1():
print("test test_printer1")
def test_printer2():
print("test test_printer2")
Currently, I am getting this:
example3.py::test_printer1
session fixture
function setup
test test_printer1
example3.py::test_printer2
function setup
test test_printer2
But, I want to get this:
example3.py::test_printer1
function setup
session fixture
test test_printer1
example3.py::test_printer2
function setup
test test_printer2
Notice that setup_function must be executed prior to every single test case.
¿Is there any way to achieve such an aim? I mean to have a setup_function that gets executed prior to any fixture disregarding its scope on Pytest.
If Pytest is not a requirement you can use unittest to do that, i personally do exactly this in one of my projects.
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
self.foo = 'bar'
def tearDown(self):
self.foo = None
Then you can create all your test cases as methods inside that class and every single one will have the setup function running before it and the teardown after it. Like so:
def test_foo(self):
self.assertTrue(self.foo == 'bar')

Parameterized fixture with pytest-datafiles

I have a Python function that processes different types of files for which I want set up a testing scheme. For each of the different file types it can handle I have a test file. I'd like to use pytest-datafiles so the tests automatically get performed on copies in a tmpdir. I'm trying to setup a parameterized fixture, similar to #pytest.fixture(params=[...]), so that the test function automatically gets invoked for each test file. How do I achieve this?
I tried the code below, but my datafiles are not copied to the tmpdir, and the test collection fails, because the test_files() fixture does not yield any output. I'm quite new to pytest, so possibly I don't fully understand how it works.
#pytest.fixture(params = [1,2])
#pytest.mark.datafiles('file1.txt','file1.txt')
def test_files(request,datafiles):
for testfile in datafiles.listdir():
yield testfile
#pytest.fixture(params = ['expected_output1','expected_output2'])
def expected_output(request):
return request.param
def my_test_function(test_files,expected_output):
assert myFcn(test_files) == expected_output
After reading up on fixtures and marks I conclude that the way I tried to use pytest.mark.datafiles is probably not possible. Instead I used the built-in tmpdir functionality in pytest, as demonstrated below. (Also, the fact that I named my fixture function test_files() may have messed things up since pytest would recognize it as a test function.)
testFileNames = {1:'file1.txt', 2:'file2.txt'}
expectedOutputs = {1:'expected_output1', 2:'expected_output2'}
#pytest.fixture(params = [1,2])
def testfiles(request,tmpdir):
shutil.copy(testFileNames[request.param],tmpdir)
return os.path.join(tmpdir,testFileNames[request.param])
#pytest.fixture(params = [1,2])
def expected_output(request):
return expectedOutputs[request.param]
def my_test_function(testfiles,expected_output):
assert myFcn(testfiles) == expected_output

how to return values from a function that has #given constructor

def fixed_given(self):
return #given(
test_df=data_frames(
columns=columns(
["float_col1"],
dtype=float,
),
rows=tuples(
floats(allow_nan=True, allow_infinity=True)),
)
)(self)
#pytest.fixture()
#fixed_given
def its_a_fixture(test_df):
obj = its_an_class(test_df)
return obj
#pytest.fixture()
#fixed_given
def test_1(test_df):
#use returned object from my fixture here
#pytest.fixture()
#fixed_given
def test_2(test_df):
#use returned object from my fixture here
Here, I am creating my test dataframe in a seperate function to use it commonly across all functions.
And then creating a pytest fixture to instantiate a class by passing the test dataframe generated by a fixed given function.
I am finding a way to get a return value from this fixture.
But the problem i am using a given decorator, its doesn't allow return values.
is there a way to return even after using given decorator?
It's not clear what you're trying to acheive here, but reusing inputs generated by Hypothsis gives up most of the power of the framework (including minimal examples, replaying failures, settings options, etc.).
Instead, you can define a global variable for your strategy - or write a function that returns a strategy with #st.composite - and use that in each of your tests, e.g.
MY_STRATEGY = data_frames(columns=[
column(name="float_col1", elements=floats(allow_nan=True, allow_infinity=True))
])
#given(MY_STRATEGY)
def test_foo(df): ...
#given(MY_STRATEGY)
def test_bar(df): ...
Specifically to answer the question you asked, you cannot get a return value from a function decorated with #given.
Instead of using fixtures to instantiate your class, try using the .map method of a strategy (in this case data_frames(...).map(its_an_class)), or the builds() strategy (i.e. builds(my_class, data_frames(...), ...)).

pytest - default fixture parameter value

I wrote a fixture in pytest which was not parametrized but is used by a lot of tests. Later I needed to parametrize this fixture.
In order to not to have to mark.parametrize all the old tests I did the following:
def ldap_con(request):
try:
server_name = request.param
except AttributeError:
server_name = "ldaps://my_default_server"
c = Connection(server_name, use_ssl=True)
yield c
c.unbind()
Now I can have both:
def test_old(ldap_con):
run_test_to_default_connection(ldap_con)
#pytest.mark.parametrize('ldap_con', ['mynewserver'], indirect=True)
def test_new(ldap_con):
run_test_to_new_connection(ldap_con)
The solution has several drawbacks:
I am catching an arbitrary Attribute Error (there might be another)
It does not take into account named parameters
It is not clear to a reader that there is a default value
Is there a standard way to define a default value for a fixture parameter?
Indirect parametrization is messy. To avoid that, I usually write fixture so that it returns a function. I will end up writing it this way:
def ldap_con():
def _ldap_con(server_name="ldaps://my_default_server"):
c = Connection(server_name, use_ssl=True)
yield c
c.unbind()
return _ldap_con
def test_old(ldap_con):
run_test_to_default_connection(ldap_con())
#pytest.mark.parametrize('server', ['mynewserver'])
def test_new(server):
run_test_to_new_connection(ldap_con(server))

Show docstrings on every function call

Let's say I have a code like this:
class NewTestCase(unittest.TestCase, CommonMethods):
def setUp(self):
self.shortDescription()
def test_01_sample test(self):
"""Testing something"""
self.create_account(self.arg['account'])
assert ...
...
class CommonMethods():
def create_account(self, account):
"""Creating account"""
...
if __name__ == '__main__':
unittest.main(verbosity=2, warnings='ignore')
I want to show the docstrings of all methods defined / created by me ('Testing something' and 'Creating account'), but the execution shows 'Testing something' only. Any tip?
Maybe there is an option for that in the unittest module, but I doubt it; otherwise, how would that module distinguish between your methods and functions and all sorts of library functions?
What you could do is to use another function to modify the existing functions to print their Docstring and/or other useful information whenever they are called. You could make this a decorator, or just call the function manually before running the tests.
This one should 'verbosify' all the methods of a given class (only slightly tested!), and you could make similar ones for individual functions or entire modules.
def verbosify(clazz):
for name in dir(clazz):
attr = getattr(clazz, name)
if not name.startswith("__") and callable(attr):
def attr_verbose(*args, **kwargs):
print("Calling", name, args, kwargs)
print(attr.__doc__)
return attr(*args, **kwargs)
setattr(clazz, name, attr_verbose)
Just call verbosify(CommonMethods) in your main block.

Resources