Python 在单元测试期间未访问全局变量

Python 在单元测试期间未访问全局变量,python,Python,在这个问题立即被标记为重复之前,让我说,我已经试过了与我的情况最相关的两个问题。如果有必要的话,在结束这个问题之前,有人能至少看看我的问题,我将不胜感激 我有一个称为e的有限状态机对象,它是一个MCFiniteSM对象。e的核心是一个名为state_dict的字典,它存储“进程”id('1','2',等等),以及一个相关的字典,它存储关于每个“进程”的更多信息。我正在运行unittests来添加进程,根据给定的参数更改它们的状态,等等。然而,在unittest文件中的函数调用之间,有限状态机似乎

在这个问题立即被标记为重复之前,让我说,我已经试过了与我的情况最相关的两个问题。如果有必要的话,在结束这个问题之前,有人能至少看看我的问题,我将不胜感激

我有一个称为e的有限状态机对象,它是一个
MCFiniteSM
对象。e的核心是一个名为state_dict的字典,它存储“进程”id('1','2',等等),以及一个相关的字典,它存储关于每个“进程”的更多信息。我正在运行unittests来添加进程,根据给定的参数更改它们的状态,等等。然而,在unittest文件中的函数调用之间,有限状态机似乎被清除了。为了避免这种情况并保持更改,我研究了上面列出的两个问题,但是无论我尝试什么,对有限状态机的更改都不会保持不变。这是最新的文件

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'
是我希望在函数调用之间保持修改的变量。当我开始
TestFSM.test\u active\u start\u conversion
e的大小打印出0,此时它应该是6。
TestFSM.test\u add\u convert\u处理
方法成功运行

实际错误是一个关键错误。以下是堆栈跟踪:

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'
抛出错误的行是self.e.convert_state('1','S'),其中我告诉fsm更改ID为'1'的进程的状态。它认为没有ID为1的进程,并且在打印fsm的大小时,它认为有限状态机为空。这一定是因为e没有持续保持,但我不明白为什么

我尝试将
self.e
转换为
self.\uuu class\uuuuu.e
(与时间戳相同),并且只将e和时间戳保持全局,并调用
TestFSM.e
TestFSM.timestamp
来持久化更改。这两种解决方案都列在其他问题中,但它们都产生了一个关键错误。我尝试设置
setUpClass()
,但仍然产生了一个关键错误


如何保持e和时间戳?

测试方法按字母顺序执行。因此,
test\u active\u start\u conversion
test\u add\u conversion\u处理之前执行


但是,实际上,您的测试应该是独立的-您应该在实际的
设置
方法中进行设置,而不是在测试方法中进行设置。

测试方法是按字母顺序执行的。因此,
test\u active\u start\u conversion
test\u add\u conversion\u处理之前执行


然而,实际上您的测试应该是独立的-您应该在实际的
设置
方法中进行设置,而不是在测试方法中进行设置。

在我看来,您依赖于单元测试执行的顺序。在这种情况下,我猜测
test\u active\u start\u conversion
test\u add\u conversion\u进程之前运行。由于这些方法存储在类字典中,而dict是无序的,因此没有定义执行顺序(在某些python版本/实现中,执行顺序甚至可能因每次运行而有所不同)。谢谢。看来订购是个问题。我将测试名称更改为“test_1”和“test_2”,至少它没有抛出keyrerror。我不知道排序,因为我假设它将按顺序进行解释。您可以使用
sqlite3
shelve
数据库来持久化数据,而不是将其存储到类实例中的字典中。您还可以在一个单独的进程中运行循环(la
tornado
asyncio
)将数据持久化到字典中我建议这样做是因为它有助于线程安全、锁定、作用域,并将在测试期间保持不变<考虑到您当前的设置,代码>搁置
可能是最容易使用的。在我看来,您依赖于单元测试的执行顺序。在这种情况下,我猜测
test\u active\u start\u conversion
test\u add\u conversion\u进程之前运行。由于这些方法存储在类字典中,而dict是无序的,因此没有定义执行顺序(在某些python版本/实现中,执行顺序甚至可能因每次运行而有所不同)。谢谢。看来订购是个问题。我将测试名称更改为“test_1”和“test_2”,至少它没有抛出keyrerror。我不知道排序,因为我假设它将按顺序进行解释。您可以使用
sqlite3
shelve
数据库来持久化数据,而不是将其存储到类实例中的字典中。您还可以在一个单独的进程中运行循环(la
tornado
asyncio
)将数据持久化到字典中我建议这样做是因为它有助于线程安全、锁定、作用域,并将在测试期间保持不变<考虑到您当前的设置,代码>搁置
可能是最容易使用的。我同意测试应该是独立的。我尝试在setUpClass方法中设置e和timestamp,但这总是会产生一个KeyError。有没有一种方法可以在保持更改的同时保持测试的独立性?+1--我从未意识到unittest实际上提供了一致的顺序,但显然它提供了一致的顺序:“请注意,各种测试用例的运行顺序是通过根据字符串的内置顺序对测试函数名进行排序来确定的。”为了清晰和分解,将所有设置代码分流到
setup
方法中也有很大帮助。有时候你可以使用一个装饰器。我同意测试应该是独立的。我尝试在setUpClass方法中设置e和timestamp,但这总是会产生一个KeyError。有没有一种方法可以在保持更改的同时保持测试的独立性?+1--我从来没有意识到unittest实际上提供了一个一致的顺序,但显然它提供了:“注意