I need to setup tests depending on where or how I want to run py.test tests. I want to be able to do something like this
py.test --do_this
py.test --do_that
and retrieve the values in the setup method of a test class
class TestSuite(object):
def setup(self):
if (do_this):
...
Something like that. Can this be done? And if so, how?
From the documentation, you can add arguments to the pytest caller
# content of test_sample.py
def test_answer(do):
if do == "this":
print ("do this option")
elif do == "that":
print ("do that option")
assert 0 # to see what was printed
# content of conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption("--do", action="store", default="that",
help="my option: this or that")
#pytest.fixture
def do(request):
return request.config.getoption("--do")
Then, you can call pytest as pytest -q test_sample.py to get the default case with that and pytest -q --do=this for the other case
Related
I cannot find how to add named command line parameter to pytest command, so I can execute tests with custom parameter available as a fixture.
pytest --my-parameter
def test_something(my_parameter):
...
In order to accomplish such behaviour the pytest_addoption shall be defined and new session level fixture in combination with pytestconfig fixture shall be used
# conftest.py
import pytest
def pytest_addoption(parser):
parser.addoption(
"--my-parameter", action="store", default=None,
help=("Parameter description")
)
#pytest.fixture(scope='session')
def my_parameter(pytestconfig):
""" Description of changes triggered by parameter. """
param = pytestconfig.getoption("--my-parameter")
if param is None:
assert False, '--my-parameter parameter must be supplied in order to run test suite.'
return param
# tests.py:
import pytest
def test_something(my_parameter):
...
I am having a testsuite which is a class and each testmethod is a testcase. I am also having a fixture for each method (testcase) which does some basic things. I am having a strange requirement where I want to skip all the testcases in the test suite if testfixture fails.
below is the sample suite I am having
class TestFeature:
#pytest.fixture(scope="function", autouse=True)
def _wrapper(self):
print("Some precomditions")
yield
print("some post conditions")
def test_first_testcase(self):
print("First testcas")
def test_second_testcase(self):
print("second testcas")
def test_third_testcase(self):
print("Third testcas")
Now I want if my fixture fails, I want to abort this test suite. Suppose My first testcase failed. Fixture for next test case failed. I want to abort the suite and do not want to execute third testcase.
How to do this in pytest
pytest allows you to do it by using the x flag:
pytest -x
You can also use maxfail flag if you wish to customize the number of failures before quitting:
--maxfail=NUMBER
In case you need to exit the test suite from within your code, you can use the exit method:
import pytest
pytest.exit()
I have the following as conftest.py -->
def pytest_addoption(parser):
parser.addoption("--browser")
parser.addoption("--osType", help="Type of operating system")
parser.addoption("--hostURL", action="store", help="prod, stage, or dev")
#pytest.fixture(scope="session")
def browser(request):
return request.config.getoption("--browser")
#pytest.fixture(scope="session")
def osType(request):
return request.config.getoption("--osType")
#pytest.fixture(autouse=True)
def hostURL(request):
return request.config.getoption("--hostURL")
I would like to use the --hostURL flag to pass in value such as prod, stage or dev.
Here's how my test_TheMainTest.py looks -->
import unitest
import pytest
class CheckStatusCodeTest(unittest.TestCase, LoginPage, CustomSeleniumDriver):
def test_CheckStatusCodeOfPages(self, hostURL):
self.login(hostURL)
When I run the above test using pytest -q -s --hostURL prod I get the following error -->
TypeError: test_CheckStatusCodeOfCRPages() missing 1 required positional argument: 'hostURL'
Quoting the docs:
Note
unittest.TestCase methods cannot directly receive fixture arguments as implementing that is likely to inflict on the ability to run general unittest.TestCase test suites.
However, you can still pass regular fixture values to unittest-style tests using autouse fixtures:
class CheckStatusCodeTest(unittest.TestCase):
#pytest.fixture(autouse=True)
def _pass_fixture_value(self, hostURL):
self._hostURL = hostURL
def test_CheckStatusCodeOfPages(self):
assert self._hostURL
You can also check out this answer of mine tackling the same issue for more examples.
Another possibility is to implement an autouse fixture that modifies the test class explicitly. This is useful if you have lots of test classes that should have the identical setup:
#pytest.fixture(scope="class")
def set_fixture_value_to_class(request, hostURL):
request.cls._hostURL = hostURL
#pytest.mark.usefixtures('set_fixture_value_to_class')
class CheckStatusCodeTest(unittest.TestCase):
def test_CheckStatusCodeOfPages(self):
assert self._hostURL
#pytest.mark.usefixtures('set_fixture_value_to_class')
class AnotherTest(unittest.TestCase):
def test_spam(self):
assert self._hostURL
In this case, no need to copy the same fixture to each test class. Just mark all relevant test classes and you're good to go.
How to execute setup and teardown functions once for all nosetests tests?
def common_setup():
#time consuming code
pass
def common_teardown():
#tidy up
pass
def test_1():
pass
def test_2():
pass
#desired behavior
common_setup()
test_1()
test_2()
common_teardown()
Note that there exists a similar question with an answer that is not working with python 2.7.9-1, python-unittest2 0.5.1-1 and python-nose 1.3.6-1 after replacing the dots with pass and adding the line import unittest.
Unfortunately my reputation is too low to comment on that.
You can have a module level setup function. According to nose documentation:
Test modules offer module-level setup and teardown; define the method
setup, setup_module, setUp or setUpModule for setup, teardown,
teardown_module, or tearDownModule for teardown.
So, more specifically, for your case:
def setup_module():
print "common_setup"
def teardown_module():
print "common_teardown"
def test_1():
print "test_1"
def test_2():
print "test_2"
Running test gives you:
$ nosetests common_setup_test.py -s -v
common_setup
common_setup_test.test_1 ... test_1
ok
common_setup_test.test_2 ... test_2
ok
common_teardown
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
It does not matter which name you choose, so both setup and setup_module would work the same, but setup_module has more clarity to it.
I am writing a set of test cases say Test1, Test2 in a test module.
Is there a way to skip Test1 or selectively execute only Test2 in that module using the command nose.main()?
My module contains,
test_module.py,
class Test1:
setUp(self):
print('setup')
tearDown(self):
print('teardown')
test(self):
print('test1')
class Test2:
setUp(self):
print('setup')
tearDown(self):
print('teardown')
test(self):
print('test2')
I run it from a different python file using,
if __name__ == '__main__':
nose.main('test_module')
The notion of skipping test and not running a test are different in the context of nose: skipped tests will be reported as skipped at the end of the test result. If you want to skip the test you would have to monkey patch your test module with decorators or do some other dark magic.
But if you want to just not run a test, you can do it the same way you would do it from the command line: using --exclude option. It takes a regular expression of the test you do not want to run. Something like this:
import sys
import nose
def test_number_one():
pass
def test_number_two():
pass
if __name__ == '__main__':
module_name = sys.modules[__name__].__file__
nose.main(argv=[sys.argv[0],
module_name,
'--exclude=two',
'-v'
])
Running the test will give you:
$ python stackoverflow.py
stackoverflow.test_number_one ... ok
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK