1

I wanted to call setUpClass and tearDownClass so that setup and teardown would be performed only once for each test. However, it keeps failing for me when I call tearDownClass. I only want to record 1 test result, either PASS if both tests passed or FAIL if both tests failed. If I call only setup and tearDown then all works fine:

Calling setUpClass and tearDownClass:

#!/usr/bin/python

import datetime
import itertools
import logging
import os
import sys
import time
import unittest

LOGFILE = 'logfile.txt'

class MyTest(unittest.TestCase):

    global testResult
    testResult = None

    @classmethod
    def setUpClass(self):

        ## test result for DB Entry:
        self.dbresult_dict = {
             'SCRIPT'       : 'MyTest.py',
             'RESULT'      : testResult,
        }

    def test1(self):

       expected_number = 10
       actual_number = 10

       self.assertEqual(expected_number, actual_number) 

   def test2(self):

       expected = True
       actual = True

       self.assertEqual(expected, actual)


   def run(self, result=None):
       self.testResult = result
       unittest.TestCase.run(self, result)

   @classmethod
   def tearDownClass(self):
       ok = self.testResult.wasSuccessful()
       errors = self.testResult.errors
       failures = self.testResult.failures
       if ok:
           self.dbresult_dict['RESULT'] = 'Pass'
       else:
           logging.info(' %d errors and %d failures',
                 len(errors), len(failures))
           self.dbresult_dict['RESULT'] = 'Fail'

if __name__ == '__main__':
   logger = logging.getLogger()
   logger.addHandler(logging.FileHandler(LOGFILE, mode='a'))
   stderr_file = open(LOGFILE, 'a')

   runner = unittest.TextTestRunner(verbosity=2, stream=stderr_file, descriptions=True)
   itersuite = unittest.TestLoader().loadTestsFromTestCase(MyTest)
   runner.run(itersuite)
   sys.exit()
   unittest.main(module=itersuite, exit=True)

stderr_file.close()

Error:

test1 (__main__.MyTest) ... ok
test2 (__main__.MyTest) ... ok
ERROR
===================================================================
ERROR: tearDownClass (__main__.MyTest)
-------------------------------------------------------------------
Traceback (most recent call last):
   File "testTearDownClass.py", line 47, in tearDownClass
    ok = self.testResult.wasSuccessful()
AttributeError: type object 'MyTest' has no attribute 'testResult'
----------------------------------------------------------------------
Ran 2 tests in 0.006s
FAILED (errors=1)
roippi
  • 25,533
  • 4
  • 48
  • 73
user2766739
  • 467
  • 2
  • 8
  • 15
  • You're using the framework quite differently from how it was designed. Just have the tests record separate results, then do aggregation in whatever you use to process results. – Marcin Sep 02 '14 at 19:27
  • You explicitly told python to make `testResult` a *global* instead of a class attribute. Delete the line `global testResult`. There are a host of other issues (which I won't get into) but that's your most immediate one. – roippi Sep 02 '14 at 19:35
  • Hi, I removed the 'global testResult' but still got same error. Should I just record test result in each test function? Or use do TestSuite.addTest for each test function? – user2766739 Sep 02 '14 at 20:26

2 Answers2

0

like @Marcin already pointed out, you're using the Unittest-Framework in a way it isn't intended.

  1. To see if the tests are successful you check the given values with the expected, like you already did: assertEqual(given, expected). Unittest will then collect a summary of failed ones. you don't have to do this manually.
  2. If you want to check that two tests need to be together successful or fail together, these should be combined in ONE Test, maybe as a additionally one, if the individual Tests need to be checked as well. This is nothing you want to save and load afterwards. The tests itself should be as stateless as possible.
  3. When you say you want to run the SetUp and TearDown 'once per test', do you mean once per test-method or per test-run? This is different if you have more than one test-method inside your class:
  • setUp() Will be called before each test-method
  • tearDown() Will be called after each test-method
  • setUpClass() Will be called once per class (before the first test-method of this class)
  • tearDownClass() Will be called once per class (after the last test-method of this class)

Here's the official documentation

Here's a related answer

Asriel
  • 81
  • 10
-4

Change tearDownClass(self) to tearDownClass(cls) and setUpClass(self) to setUpClass(cls).

  • 4
    `self` and `cls` as the names of the first parameter of methods is only a convertion. Changing the name has no effect on the behavior. – Terry Jan Reedy Feb 27 '15 at 02:47