pytest is not running any tests - python

My tests are in the following folder structure. Though I have also placed a sample test in the root, which doesn't work either. I get no tests ran in 6.08s
root/
test/
integrations/
test_sample.py
__init__.py
__init__.py
I have tried using the command pytest by itself as well as specifying the test location pytest ./test/integrations/test_sample.py
I've been using a class to define multiple tests, but simple functions aren't running either.
Class:
class TestClass:
def add(self):
pass
Function:
def add():
pass

You need to write a test as function with a name beginning with test. See pytest's docs: test-discovery.
In this test or function:
instantiate your class
and run the class' method or function
import pytest
# this class will be tested
class ClassUnderTest:
def add(self):
return "it ran"
# This test will run because its name begins with "test"
def test_add():
cls = ClassUnderTest()
assert cls.add() == "it ran"
# This won't run because its name does not begin with "test"
def run_add():
cls = ClassUnderTest()
assert cls.add() == "it ran"
# ===== 1 passed in 0.05s =====

Methods name should start with test_. (inside class or out) is this what you're missing?

Related

Append the nose #attr to the test name

I am able to setup nose tests to run with the #attr tag. I am now interested in know if I can append to the end of the test name, the #attr tag? What we are trying to do is add a tag if our tests run into an issue and we write up a defect for it, we would then put the defect number as an #attr tag. Then when we run we could easily identify which tests have open defects against them.
Just wondering if this is even possible, and where to go to see how to set it up?
EDIT RESULTS RUNNING WITH ANSWER:
Test Results:
So I sort of know what is going on, if I have the #fancyattr() at the class level it picks it up and changes the name of the class. When I put the #fancyattr() at the test level it is not changing the name of the test, which is what I need for it to do.
For example - Changes the name of the class:
#dms_attr('DMSTEST')
#attr('smoke_login', 'smoketest', priority=1)
class TestLogins(BaseSmoke):
"""
Just logs into the system and then logs off
"""
def setUp(self):
BaseSmoke.setUp(self)
def test_login(self):
print u"I can login -- taking a nap now"
sleep(5)
print u"Getting off now"
def tearDown(self):
BaseSmoke.tearDown(self)
This is what I need and it isn't working:
#attr('smoke_login', 'smoketest', priority=1)
class TestLogins(BaseSmoke):
"""
Just logs into the system and then logs off
"""
def setUp(self):
BaseSmoke.setUp(self)
#dms_attr('DMSTEST')
def test_login(self):
print u"I can login -- taking a nap now"
sleep(5)
print u"Getting off now"
def tearDown(self):
BaseSmoke.tearDown(self)
Updated screenshot with what I am seeing with __doc__:
Here is how to do it with args type attributes:
rename_test.py:
import unittest
from nose.tools import set_trace
def fancy_attr(*args, **kwargs):
"""Decorator that adds attributes to classes or functions
for use with the Attribute (-a) plugin. It also renames functions!
"""
def wrap_ob(ob):
for name in args:
setattr(ob, name, True)
#using __doc__ instead of __name__ works for class methods tests
ob.__doc__ = '_'.join([ob.__name__, name])
#ob.__name__ = '_'.join([ob.__name__, name])
return ob
return wrap_ob
class TestLogins(unittest.TestCase):
#fancy_attr('slow')
def test_method():
assert True
#fancy_attr('slow')
def test_func():
assert True
Running test:
$ nosetests rename_test.py -v
test_method_slow ... ok
test_func_slow ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.003s
OK
EDIT: For xunit reporting to work, test renaming should take place before running the test. You can do it on import, here is untested hack showing how to do it:
rename_test.py:
import unittest
def fancy_attr(*args, **kwargs):
"""Decorator that adds attributes to classes or functions
for use with the Attribute (-a) plugin. It also renames functions!
"""
def wrap_ob(ob):
for name in args:
setattr(ob, name, True)
ob.__doc__ = '_'.join([ob.__name__, name])
return ob
return wrap_ob
class TestLogins(unittest.TestCase):
#fancy_attr('slow')
def test_method(self):
assert True
def make_name(orig, attrib):
return '_'.join([orig, attrib])
def rename(cls):
methods = []
for key in cls.__dict__:
method = getattr(cls, key)
if method:
if hasattr(cls.__dict__[key], '__dict__'):
if 'slow' in cls.__dict__[key].__dict__:
methods.append(key)
print methods
for method in methods:
setattr(cls, make_name(method, 'slow'), cls.__dict__[key])
delattr(cls, method)
rename(TestLogins)
#fancy_attr('slow')
def test_func():
assert True

Testing methods each with a different setup/teardown

I'm testing a class, with many test methods. However, each method has a unique context. I then write my code as following:
class TestSomeClass(unittest.TestCase):
def test_a():
with a_context() as c:
pass
def test_b():
with b_context() as c:
pass
def test_c():
with c_context() as c:
pass
However, the context managers are irrelevant to the test case, and produce temporary files. So as to not pollute the file system when the test fails, I would like to use each context manager in a setup/teardown scenario.
I've looked at nose's with_setup, but the docs say that is meant for functions only, not methods. Another way is to move the test methods to separate classes each with a setup/teardown function. What's a good way to do this?
First of all, I'm not sure why what you have isn't working. I wrote some test code, and it shows that the exit code always gets called, under the unittest.main() execution environment. (Note, I did not test nose, so maybe that's why I couldn't replicate your failure.) Maybe your context manager is broken?
Here's my test:
import unittest
import contextlib
import sys
#contextlib.contextmanager
def context_mgr():
print "setting up context"
try:
yield
finally:
print "tearing down context"
class TestSomeClass(unittest.TestCase):
def test_normal(self):
with context_mgr() as c:
print "normal task"
def test_raise(self):
with context_mgr() as c:
print "raise task"
raise RuntimeError
def test_exit(self):
with context_mgr() as c:
print "exit task"
sys.exit(1)
if __name__ == '__main__':
unittest.main()
By running that with $ python test_test.py I see tearing down context for all 3 tests.
Anyway, to answer your question, if you want a separate setup and teardown for each test, then you need to put each test in its own class. You can set up a parent class to do most of the work for you, so there isn't too much extra boilerplate:
class TestClassParent(unittest.TestCase):
context_guard = context_mgr()
def setUp(self):
#do common setup tasks here
self.c = self.context_guard.__enter__()
def tearDown(self):
#do common teardown tasks here
self.context_guard.__exit__(None,None,None)
class TestA(TestClassParent):
context_guard = context_mgr('A')
def test_normal(self):
print "task A"
class TestB(TestClassParent):
context_guard = context_mgr('B')
def test_normal(self):
print "task B"
This produces the output:
$ python test_test.py
setting up context: A
task A
tearing down context: A
.setting up context: B
task B
tearing down context: B
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK

py.test: how to get the current test's name from the setup method?

I am using py.test and wonder if/how it is possible to retrieve the name of the currently executed test within the setup method that is invoked before running each test. Consider this code:
class TestSomething(object):
def setup(self):
test_name = ...
def teardown(self):
pass
def test_the_power(self):
assert "foo" != "bar"
def test_something_else(self):
assert True
Right before TestSomething.test_the_power becomes executed, I would like to have access to this name in setup as outlined in the code via test_name = ... so that test_name == "TestSomething.test_the_power".
Actually, in setup, I allocate some resource for each test. In the end, looking at the resources that have been created by various unit tests, I would like to be able to see which one was created by which test. Best thing would be to just use the test name upon creation of the resource.
You can also do this using the Request Fixture like this:
def test_name1(request):
testname = request.node.name
assert testname == 'test_name1'
You can also use the PYTEST_CURRENT_TEST environment variable set by pytest for each test case.
PYTEST_CURRENT_TEST environment variable
To get just the test name:
os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0]
The setup and teardown methods seem to be legacy methods for supporting tests written for other frameworks, e.g. nose. The native pytest methods are called setup_method as well as teardown_method which receive the currently executed test method as an argument. Hence, what I want to achieve, can be written like so:
class TestSomething(object):
def setup_method(self, method):
print "\n%s:%s" % (type(self).__name__, method.__name__)
def teardown_method(self, method):
pass
def test_the_power(self):
assert "foo" != "bar"
def test_something_else(self):
assert True
The output of py.test -s then is:
============================= test session starts ==============================
platform linux2 -- Python 2.7.3 -- pytest-2.3.3
plugins: cov
collected 2 items
test_pytest.py
TestSomething:test_the_power
.
TestSomething:test_something_else
.
=========================== 2 passed in 0.03 seconds ===========================
Short answer:
Use fixture called request
This fixture has the following interesting attributes:
request.node.originalname = the name of the function/method
request.node.name = name of the function/method and ids of the parameters
request.node.nodeid = relative path to the test file, name of the test class (if in a class), name of the function/method and ids of the parameters
Long answer:
I inspected the content of request.node. Here are the most interesting attributes I found:
class TestClass:
#pytest.mark.parametrize("arg", ["a"])
def test_stuff(self, request, arg):
print("originalname:", request.node.originalname)
print("name:", request.node.name)
print("nodeid:", request.node.nodeid)
Prints the following:
originalname: test_stuff
name: test_stuff[a]
nodeid: relative/path/to/test_things.py::TestClass::test_stuff[a]
NodeID is the most promising if you want to completely identify the test (including the parameters). Note that if the test is as a function (instead of in a class), the class name (::TestClass) is simply missing.
You can parse nodeid as you wish, for example:
components = request.node.nodeid.split("::")
filename = components[0]
test_class = components[1] if len(components) == 3 else None
test_func_with_params = components[-1]
test_func = test_func_with_params.split('[')[0]
test_params = test_func_with_params.split('[')[1][:-1].split('-')
In my example this results to:
filename = 'relative/path/to/test_things.py'
test_class = 'TestClass'
test_func = 'test_stuff'
test_params = ['a']
# content of conftest.py
#pytest.fixture(scope='function', autouse=True)
def test_log(request):
# Here logging is used, you can use whatever you want to use for logs
log.info("STARTED Test '{}'".format(request.node.name))
def fin():
log.info("COMPLETED Test '{}' \n".format(request.node.name))
request.addfinalizer(fin)
Try my little wrapper function which returns the full name of the test, the file and the test name. You can use whichever you like later.
I used it within conftest.py where fixtures do not work as far as I know.
def get_current_test():
full_name = os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]
test_file = full_name.split("::")[0].split('/')[-1].split('.py')[0]
test_name = full_name.split("::")[1]
return full_name, test_file, test_name
You might have multiple tests, in which case...
test_names = [n for n in dir(self) if n.startswith('test_')]
...will give you all the functions and instance variables that begin with "test_" in self. As long as you don't have any variables named "test_something" this will work.
You can also define a method setup_method(self, method) instead of setup(self) and that will be called before each test method invocation. Using this, you're simply given each method as a parameter. See: http://pytest.org/latest/xunit_setup.html
You could give the inspect module are try.
import inspect
def foo():
print "My name is: ", inspect.stack()[0][3]
foo()
Output: My name is: foo
Try type(self).__name__ perhaps?

How to call setup once for all tests and teardown after all are finished

I have a bunch of tests written using pytest. There are all under a directory dir. For example:
dir/test_base.py
dir/test_something.py
dir/test_something2.py
...
The simplified version of code in them is as follows:
test_base.py
import pytest
class TestBase:
def setup_module(module):
assert False
def teardown_module(module):
assert False
test_something.py
import pytest
from test_base import TestBase
class TestSomething(TestBase):
def test_dummy():
pass
test_something2.py
import pytest
from test_base import TestBase
class TestSomethingElse(TestBase):
def test_dummy2():
pass
All my test_something*.py files extend the base class in test_base.py. Now I wrote setup_module(module) and teardown_module(module) methods in test_base.py. I was expecting the setup_module to be called once for all tests, and teardown_module() to be called at the end, once all tests are finished.
But the functions don’t seem to be getting called? Do I need some decorators for this to work?
The OP's requirement was for setup and teardown each to execute only once, not one time per module. This can be accomplished with a combination of a conftest.py file, #pytest.fixture(scope="session") and passing the fixture name to each test function.
These are described in the Pytest fixtures documentation
Here's an example:
conftest.py
import pytest
#pytest.fixture(scope="session")
def my_setup(request):
print '\nDoing setup'
def fin():
print ("\nDoing teardown")
request.addfinalizer(fin)
test_something.py
def test_dummy(my_setup):
print '\ntest_dummy'
test_something2.py
def test_dummy2(my_setup):
print '\ntest_dummy2'
def test_dummy3(my_setup):
print '\ntest_dummy3'
The output when you run py.test -s:
collected 3 items
test_something.py
Doing setup
test_dummy
.
test_something2.py
test_dummy2
.
test_dummy3
.
Doing teardown
The name conftest.py matters: you can't give this file a different name and expect Pytest to find it as a source of fixtures.
Setting scope="session" is important. Otherwise setup and teardown will be repeated for each test module.
If you'd prefer not to pass the fixture name my_setup as an argument to each test function, you can place test functions inside a class and apply the pytest.mark.usefixtures decorator to the class.
Put setup_module and teardown_module outside of a class on module level. Then add your class with your tests.
def setup_module(module):
"""..."""
def teardown_module(module):
"""..."""
class TestSomething:
def test_dummy(self):
"""do some tests"""
For more info refer to this article.
setup_module/teardown_module are called for the module where the eventual (derived) tests are defined. This also allows to customize the setup. If you only ever have one setup_module you can put it to test_base.py and import it from the other places. HTH.
First of all it is a good practice to put all tests in a module called "tests":
<product>
...
tests/
__init__.py
test_something.py
Secondly I think you should use setup_class/teardown_class methods in your base class:
import unittest
class MyBase(unittest.TestCase):
#classmethod
def setup_class(cls):
...
#classmethod
def teardown_class(cls):
...
More info: http://pytest.org/latest/xunit_setup.html

python unittest methods

Can I call a test method from within the test class in python? For example:
class Test(unittest.TestCase):
def setUp(self):
#do stuff
def test1(self):
self.test2()
def test2(self):
#do stuff
update: I forgot the other half of my question. Will setup or teardown be called only after the method that the tester calls? Or will it get called between test1 entering and after calling test2 from test1?
This is pretty much a Do Not Do That. If you want tests run in a specific order define a runTest method and do not name your methods test....
class Test_Some_Condition( unittest.TestCase ):
def setUp( self ):
...
def runTest( self ):
step1()
step2()
step3()
def tearDown( self ):
...
This will run the steps in order with one (1) setUp and one (1) tearDown. No mystery.
Try running the following code:
import unittest
class Test(unittest.TestCase):
def setUp(self):
print 'Setting Up'
def test1(self):
print 'In test1'
self.test2()
def test2(self):
print 'In test2'
def tearDown(self):
print 'Tearing Down'
if __name__ == '__main__':
unittest.main()
And the results is:
Setting Up
In test1
In test2
Tearing Down
.Setting Up
In test2
Tearing Down
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
Now you see, setUp get called before a test method get called by unittest, and tearDown is called after the call.
All methods whose name begins with the string 'test' are considered unit tests (i.e. they get run when you call unittest.main()). So you can call methods from within the Test class, but you should name it something that does not start with the string 'test' unless you want it to be also run as a unit test.
sure, why not -- however that means test2 will be called twice -- once by test1 and then again as its own test, since all functions named test will be called.
Yes to both:
setUp will be called between each test
test2 will be called twice.
If you would like to call a function inside a test, then omit the test prefix.

Categories