Jeremy Fisher
Jeremy Fisher

Reputation: 2782

Global variable not accessed during unittests

Before this question is immediately marked as a duplicate let me say that I have already tried every solution which were the two questions most relevant to my situation. I would appreciate it if someone could at least look at my particular issue before closing this question if necessary.

I have a finite state machine object called e which is a MCFiniteSM object. At the core of e is a dictionary called state_dict which stores "process" ids ('1', '2', etc) and an associated dictionary which stores more information about each "process". I am running unittests to add processes, changes their states based on given parameters, etc. However, in between function calls in the unittest file the finite state machine seems to be cleared. I have looked at the two questions listed above in order to avoid this and persist changes but no matter what I try the changes to the finite state machine are not persisted. Here is the uniitest file.

from finite_state_machine import MCFiniteSM
from unittest import TestLoader, TestCase, main as unimain
from datetime import datetime
import time, calendar

class MyUnitTest(TestCase):

    @classmethod
    def setUpClass(cls):
        cls.e = MCFiniteSM()
        cls.timestamp = datetime.strftime(datetime.fromtimestamp(calendar.timegm(time.gmtime())), '%Y/%m/%d %H:%M:%S')

class TestFSM(MyUnitTest):

    @classmethod
    def setUpClass(cls):
        super(TestFSM, cls).setUpClass()
        #e = MCFiniteSM()
        #timestamp = datetime.strftime(datetime.fromtimestamp(calendar.timegm(time.gmtime())), '%Y/%m/%d %H:%M:%S')

    def test_add_convert_processes(self):

        self.e.add_process('1', 'S', self.timestamp, 100, 'start message for process 1')
        self.e.add_process('2', 'S', self.timestamp, 200, 'start message for process 2')
        self.e.add_process('3', 'S', self.timestamp, 300, 'start message for process 3')
        self.e.add_process('4', 'S', self.timestamp, 400, 'start message for process 4')
        self.e.add_process('5', 'S', self.timestamp, 500, 'start message for process 5')
        self.e.add_process('6', 'S', self.timestamp, 600, 'start message for process 6')

        self.assertEqual(self.e.state_dict['1'], {'id':'1', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':100, 'message': 'start message for process 1'})
        self.assertEqual(self.e.state_dict['2'], {'id':'2', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':200, 'message': 'start message for process 2'})
        self.assertEqual(self.e.state_dict['3'], {'id':'3', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':300, 'message': 'start message for process 3'})
        self.assertEqual(self.e.state_dict['4'], {'id':'4', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':400, 'message': 'start message for process 4'})
        self.assertEqual(self.e.state_dict['5'], {'id':'5', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':500, 'message': 'start message for process 5'})
        self.assertEqual(self.e.state_dict['6'], {'id':'6', 'message_type': 'S', 'timestamp':self.timestamp, 'state': 'i', 'threshold':600, 'message': 'start message for process 6'})

        self.e.convert_state('1', 'S')
        self.e.convert_state('2', 'S')
        self.e.convert_state('3', 'S')
        self.e.convert_state('4', 'S')
        self.e.convert_state('5', 'S')
        self.e.convert_state('6', 'S')

        self.assertEqual(self.e.state_dict['2']['state'], 'a')
        self.assertEqual(self.e.state_dict['3']['state'], 'a')
        self.assertEqual(self.e.state_dict['4']['state'], 'a')

        self.e.add_process('2', 'E', self.timestamp, None, 'end message for process 2')
        self.e.add_process('3', 'E', self.timestamp, None, 'end message for process 3')
        self.e.add_process('4', 'E', self.timestamp, None, 'end message for process 4')

        self.assertEqual(self.e.state_dict['2']['state'], 'i')
        self.assertEqual(self.e.state_dict['3']['state'], 'i')
        self.assertEqual(self.e.state_dict['4']['state'], 'i')

    def test_active_start_conversion(self):
        print self.e
        print 'trying...'
        import sys
        from StringIO import StringIO

        orig = sys.stdout
        try:
            output = StringIO()
            sys.stdout = output
            self.e.convert_state('1', 'S')
            out = output.getvalue().strip()
            test = "Process ID:", '1', "\n" \
            "Process Message Type:", 'S', "\n" \
            "Process timestamp:", self.timestamp, "\n" \
            "Process Threshold:", 100, "\n" \
            "Process Message:", 'start message for process 1', "\n" \
            "Log Message:", "PROCESS WITH ID 1 SENT MULTIPLE START MESSAGES", "\n"
            self.assertEqual(out, test)
        finally:
            sys.stdout = orig

if __name__ == '__main__':
        unimain()

'e' is the variable I want to keep modified between function calls. When I get down to TestFSM.test_active_start_conversion the size of e prints out 0, when it should be 6. The TestFSM.test_add_convert_processes method runs successfully.

The actual error is a key error. Here is the stack trace:

Error
Traceback (most recent call last):
  File "/home/Desktop/fsm_unit_tests.py", line 68, in test_active_start_conversion
    self.e.convert_state('1', 'S')
  File "/home/Desktop/finite_state_machine.py", line 26, in convert_state
    cb_id = self.state_dict[id]['id']
KeyError: '1'

The line where the error is thrown is the self.e.convert_state('1', 'S') where I am telling the fsm to change the state of the process with ID '1'. It believes that there is no process with ID 1 and upon printing the size of the fsm it believes the finite state machine is empty. This must be due to the fact that e is not continually maintained but I do not see why.

I have tried converting self.e to self.__class__.e (same with timestamp) as well as just keeping e and timestamp global and calling TestFSM.e and TestFSM.timestamp to persist changes. Both these solutions were listed in the other questions, both of them still produced a Key Error. I tried setting up setUpClass(), but that still produced a key error.

How can I persist e and timestamp?

Upvotes: 1

Views: 1164

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599610

Test methods are executed in alphabetical order. So test_active_start_conversion is executed before test_add_convert_processes.

However, really your tests should be independent - you should be doing the set up in the actual setUp method, not in a test method.

Upvotes: 5

Related Questions