Search code examples
djangopython-2.7classsubclassingclass-variables

How can i update class variable by calling a class method from a derived class


I am developing a package for my testing purpose called dbtest. This package is because i am using MySQLdb for connecting databases and hence it is very tedious task to write sql queries while testing. So i created a new package and all queries can be accessed with separate functions. I avoided django ORM because my database table have multiple foreign keys and primary keys.

Below present is a part of the package.

package.py

from django.test import TestCase
dbcon='connector'
class testcase(TestCase):
    flag_user=[]

@classmethod                                                               
def setUpClass(cls):

    global dbcon
    dbcon=MySQLdb.connect(host=dbHost,port=dbPort,user=dbUser,passwd=dbPasswd,db=dbname)
    super(testcase, cls).setUpClass()

    cursor = dbcon.cursor()
    sql=open("empty.sql").read()
    cursor.execute(sql)
    cursor.close()

    views.MySQLdb=Mockdb()

@classmethod
def tearDownClass(cls):
   dbcon.close()

def user_table(self,username=username,email=email):

    cache=[username]
    self.flag_user.append(cache)
    cmpdata=(username,email)
    insert_table(tablename_user,cmpdata)

def delete(self,table):
    last_entry=self.flag_user[-1]
    query_user = 'delete from USER where USERNAME=%s'
    cursor=dbcon.cursor()
    query=eval('query_%s'%table)
    cursor.execute(query,last_entry)
    dbcon.commit()
    del self.flag_user[-1]

tests.py

from package import testcase
class showfiles(testcase):

    def setUp(self):
      print "setup2"
      self.user_table(username='vishnu',email='vishnu@clartrum.com')

    def tearDown(self):
      print "teardown2"
      self.delete("user")

    def test_1(self):
      print "test dbtest link feature"


    def test_2(self):
      print "test health/errorfiles with valid device"
      self.user_table(username='vishnu',email='vishnu@clartrum.com')

The insert_table in package execute insert operation in sql and delete method deletes the last entry from user. empty.sql creates tables for the database. Actually when i run the tests, finally the flag_user should contain only [['vishnu']]. But i get [['vishnu'],['vishnu']] and this is because delete function in teardown doesn't updating the value.

I think this is due to class instances ? Am i right or not?


Solution

  • Here :

    class testcase(TestCase):
        flag_user=[]
    

    you create flag_user as a class attribute (shared by all instances).

    Then here:

    def user_table(self,username=username,email=email):
        cache=[username]
        self.flag_user.append(cache)
    

    You append to the (class level) flag_user attribute (it's accessed thru the instance but it's still the class attribute)

    But here:

    def delete(self,table):
        delete_table(tablename)
        self.flag_user=[]
    

    you create a flag_user attribute on the instance itself, which is totally disconnected from the eponym class attribute.

    The simplest solution is to use an instance attribute right from the start instead of using a class attribute:

    # package.py
    
    from django.test import TestCase
    dbcon='connector'
    
    class testcase(TestCase):
        def setUp(self): 
            self.flag_user = []
    

    and don't forget to call testcase.setUp in child classes:

    # tests.py
    
    from package import testcase
    class showfiles(testcase):
    
        def setUp(self):
          super(showfile, self).setUp()
          self.user_table(username='vishnu',email='vishnu@clartrum.com')
    

    The alternative solution if you really want a class attribute (I can't imagine why you would but...) is to modify testcase.delete() so it really clears the flag_user class attribute instead of creating an instance attribute, which is done by explicitely asking python to rebind the attribute on the class itself (type(obj) returns obj.__class__ which is the class the instance belongs to):

    def delete(self,table):
        delete_table(tablename)
        type(self).flag_user = []