Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For unittest.TestCase subclass, unable to get class attribute when testcases are executed by run method

I want to set a value to a class attribute inside a test method and use the value with same class attribute in another test method. When I tried in normal way by executing test cases with run method, got error as AttributeError: 'Unit' object has no attribute 'b'. Anyway, I found other solutions by using global variable and one more by assigning the class to a variable. May I know the reason why I am not able to retrieve class attribute which I had set the same using another method? Also, could you help me explaining the actual process with run method... Thanks in advance.

Here is a sample code which I tried:

import unittest
class Unit(unittest.TestCase):
    def test_i(self):
        self.b=20
    def test_j(self):
        print self.b


suite=unittest.TestLoader().loadTestsFromTestCase(Unit)
unittest.TextTestRunner(verbosity=2).run(suite)
test_i (__main__.Unit) ... ok
test_j (__main__.Unit) ... ERROR

======================================================================
ERROR: test_j (__main__.Unit)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<pyshell#52>", line 5, in test_j
AttributeError: 'Unit' object has no attribute 'b'

----------------------------------------------------------------------
Ran 2 tests in 0.078s

FAILED (errors=1)
<unittest.runner.TextTestResult run=2 errors=1 failures=0>


    #The two ways which I solved...
    #1.By Assinging class to a variable
 import unittest
 class Unit(unittest.TestCase):
         def test_i(self):
        Class=Unit
        Class.b=20
         def test_j(self):
    print self.b


suite=unittest.TestLoader().loadTestsFromTestCase(Unit)
unittest.TextTestRunner(verbosity=2).run(suite)
test_i (__main__.Unit) ... ok
test_j (__main__.Unit) ... 20
ok

----------------------------------------------------------------------
Ran 2 tests in 0.094s

OK
<unittest.runner.TextTestResult run=2 errors=0 failures=0>



#2.By using global attribute,but I need the class attribute value to be set and        retrieved

 import unittest
 class Unit(unittest.TestCase):
     def test_i(self):
     global b,
     b=20
     def test_j(self):
     print b


suite=unittest.TestLoader().loadTestsFromTestCase(Unit)
unittest.TextTestRunner(verbosity=2).run(suite)
test_i (__main__.Unit) ... ok
test_j (__main__.Unit) ... 20
ok

----------------------------------------------------------------------
Ran 2 tests in 0.063s

OK
<unittest.runner.TextTestResult run=2 errors=0 failures=0>
like image 378
Ponds Avatar asked Dec 19 '25 03:12

Ponds


1 Answers

The attribute does not appear in the instance because each test is executed in its own instance, as you can see in this code:

import unittest
class Unit(unittest.TestCase):
    def __init__(self, *args, **kwargs):
        print('init!')
        super(Unit, self).__init__(*args, **kwargs)

    def test_i(self):
        self.b = 20
    def test_j(self):
        print(self.b)

suite = unittest.TestLoader().loadTestsFromTestCase(Unit)
unittest.TextTestRunner(verbosity=2).run(suite)

Which prints:

init!
init!
test_i (__main__.Unit) ... ok                                                                 
test_j (__main__.Unit) ... ERROR                                                              

======================================================================                        
ERROR: test_j (__main__.Unit)                                                                 
----------------------------------------------------------------------                        
Traceback (most recent call last):                                                            
  File "prova.py", line 10, in test_j                                                         
    print(self.b)
AttributeError: 'Unit' object has no attribute 'b'

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (errors=1)

Notice the two "init!" at the beginning.

This is done because each test should not depend on the other tests. There is a specific setup method, you should use it to set up the correct environment for your test.

If you want different set-ups then maybe you should consider splitting those tests in separate test cases.

Using a class variable or a global variable obviously works because the class is not deleted, and the globals are not cleared for every test.

On a side note: The fact that the class is instantiated more times is quite clear in the documentation. As you can see, when they create the TestSuite they add each new test instantiating the class and passing the test name as parameter. The loadTestsFromTestCase is simply a shortcut for creating a TestSuite in that way.

like image 68
Bakuriu Avatar answered Dec 20 '25 15:12

Bakuriu