Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 Run As -> Python unit-test. Concerning this plugin I have a few questions:

  1. 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
  2. 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 Woltan

Example:

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.

like image 280
Woltan Avatar asked Mar 25 '11 09:03

Woltan


3 Answers

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.

like image 105
Steven T. Snyder Avatar answered Nov 15 '22 12:11

Steven T. Snyder


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.

like image 41
CarlS Avatar answered Nov 15 '22 13:11

CarlS


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.

like image 2
Mark Booth Avatar answered Nov 15 '22 11:11

Mark Booth