Initialization of unit-test in PyDev?
I am unit-testing my python code in eclipse using PyDev unit-testing. I right click on the appropriate file and select Ru开发者_开发技巧n As -> Python unit-test. Concerning this plugin I have a few questions:
- Is there a way to have a setUpClass method that is being executed before any other test within this class? Currently I am only able to get setUp working, which is called before any test of the class
- Is there a way to have a global initialization that is being called before any test is executed? Something like setUpModule which I am also not able to get running using PyDev unit-testing.
Thanks in advance for any answer and comment^^
Cherio WoltanExample:
class TestClass(unittest.TestCase):
@classmethod
def setUpClass(self):
print "Setup"
def test1(self):
print "Test1"
def test2(self):
print "Test2"
If I run this with Run As -> Python unit-test the setUpClass method is not being called.
It's a PyDev bug, and has been fixed in 2.0.1.
setUpModule()
, tearDownModule()
, setUpClass()
, and tearDownClass()
are not run in the 'Python unit-test' run configuration due to the bug in PyDev 2.0.0 and earlier. In 2.0.1 they run correctly in the 'Python unit-test' and 'Python Run' configurations. I tested it myself to verify.
OK I'll give this a shot: I use Pydev and have been exploring using "nosetests" to launch tests so it's sort of relevant. My solution is a total hack, but does seem to work when saying "Debug as UnitTest" from within PyDev:
print "before any tests (global) just once..."
class MyTestCase(unittest.TestCase):
class_setup_called = False
def __init__(self, test_name):
unittest.TestCase.__init__(self, test_name)
if not self.__class__.class_setup_called:
self.setUpClass()
self.__class__.class_setup_called = True
@staticmethod
def setUpClass():
print "before first test only..."
def setUp(self):
print "before each test..."
Unfortunately this will not work when using nosetests, but it does work when running from pydev. I'm guessing that nosetests is coded to instantiate test objects before each test method is run, in which case your init method would suffice.
I can't say enough nice things about nosetests:
- support for exceptions and timed tests.
- support for annotation "attribution".
- integration with profile, coverage and xunit reporting of results.
- recursive discovery and attributed execution of test cases.
examples:
import unittest
@raises(TypeError)
def test_forexceptions(self):
pass
@attr('benchmark')
@timed(5.0)
def test_benchmark(self):
pass # do something real slow and run nosetests --with-profile -a benchmark
Additional
On further investigation if you are using nosetests then it has you covered, see "http://somethingaboutorange.com/mrl/projects/nose/1.0.0/writing_tests.html".
You can have:
package level teardowns: (these live in package level init scripts)
def setup_package()
def teardown_package()
module level teardowns:
def setup_module()
def teardown_module()
class level:
class MyTestCase(unittest.TestCase):
@classmethod
def setup_class(cls): pass
@classmethod
def teardown_class(cls): pass
and test method level:
class MyTestCase(unittest.TestCase):
def setUp(self): pass
def tearDown(cls): pass
I like to use the the "setup_" names as it nicely delineates the nose specific entry points. I've verified these work nicely when run from nosetests via the command line. But they do NOT run from Pydev "run as unit test...". A potential solution may be writing a pydev plugin that uses nose to run the tests... perhaps someone has one? You could combine my hack with the nose ones calling common module functions to do the actual work. Ideally our init() would be aware of being launched from Pydev somehow.
Edit: Summary
Stepping through your test case with the debugger, it look's like this is a limitation of PyDev's test runner not supporting setUpClass()
, at least not with 1.6.5, which I'm using.
Maybe this will be fixed in v2.0 of PyDev, but in the meantime, I think we will have to stick to using __init__()
instead, as CarlS suggests.
Details
The PyDev 1.6.5 PyDevTestSuite class uses:
def run(self, result):
for index, test in enumerate(self._tests):
if result.shouldStop:
break
test(result)
# Let the memory be released!
self._tests[index] = None
return result
which is very similar to TestSuite.run() in python 2.6, whereas TestSuite.run() in python 2.7.1's unittest does rather more:
def run(self, result, debug=False):
topLevel = False
if getattr(result, '_testRunEntered', False) is False:
result._testRunEntered = topLevel = True
for test in self:
if result.shouldStop:
break
if _isnotsuite(test):
self._tearDownPreviousClass(test, result)
self._handleModuleFixture(test, result)
self._handleClassSetUp(test, result)
result._previousTestClass = test.__class__
if (getattr(test.__class__, '_classSetupFailed', False) or
getattr(result, '_moduleSetUpFailed', False)):
continue
if not debug:
test(result)
else:
test.debug()
if topLevel:
self._tearDownPreviousClass(None, result)
self._handleModuleTearDown(result)
return result
Old answer
I suspect this may be down to the version of Python that is being referenced.
If you check Window > Preferences > PyDev > Interpreter - Python and look at which Python Interpretter is being used, you may well find that it is pre v2.7 where, if I remember correctly, setUpClass was introduced.
Reference a newer version of python and I suspect your tests will work as is.
Instead of using unittest.main()
, which automatically goes through all your test classes and individual tests, you can load the tests from each class separately and execute them at your discretion, including before each class test the necessary initializations. You can precede all that with some global initialization as well. See an example below:
import unittest
class MyTestClass1(unittest.TestCase):
def setUp(self):
pass
@classmethod
def setUpClass(cls):
pass
def test1(self):
pass
# lots of tests
class MyTestClass2(unittest.TestCase):
def setUp(self):
pass
@classmethod
def setUpClass(cls):
pass
def test1(self):
pass
# another whole lot of tests
if __name__=="__main__":
# add your global initialization code here
global_initialization()
# MyTestClass1 initialization:
MyTestClass1.setUpClass() # python 2.7 only
suite = unittest.TestLoader().loadTestsFromTestCase(MyTestClass1)
unittest.TextTestRunner().run(suite)
# MyTestClass1 initialization:
MyTestClass2.setUpClass() # python 2.7 only
suite = unittest.TestLoader().loadTestsFromTestCase(MyTestClass2)
unittest.TextTestRunner().run(suite)
The unittest
documentation has some other examples of similar use which could be of assistance.
Edit: Unbeknown to me until this moment, it seems that Python 2.7 has a setUpClass()
, (should be a class method, hence the decorator) which seems to do what you need it to . However, that's not the case in Python 2.6 and you should provide your own initialization routines.
精彩评论