Python单例 - 你如何在你的测试平台中摆脱(__del__)它们?

rh0*_*ium 1 python singleton unit-testing

非常感谢您迄今为止给我的建议.使用测试平台是这个论坛真正向我展示的亮点,因为我很感激.我的问题是我正在玩一个单身人士,通常我不会对它进行分析,但在测试平台中我需要这样做.所以有人能告诉我如何去做这件事吗?我已经开始使用一个基本示例并将其构建到测试平台中,以便我可以看到最新情况.现在我不知道怎么摆脱它!

非常感谢!!

import sys
import logging
import unittest

LOGLEVEL = logging.DEBUG

class Singleton:
    """ A python singleton """

    class __impl:
        """ Implementation of the singleton interface """
        def __init__(self):
            self.log = logging.getLogger()
            self.log.debug("Init %s" % self.__class__.__name__)

        def id(self):
            """ Test method, return singleton id """
            return id(self)


    # storage for the instance reference
    __instance = None

    def __init__(self):
        """ Create singleton instance """
        # Check whether we already have an instance
        if Singleton.__instance is None:
            # Create and remember instance
            Singleton.__instance = Singleton.__impl()

        # Store instance reference as the only member in the handle
        self.__dict__['_Singleton__instance'] = Singleton.__instance

    def __getattr__(self, attr):
        """ Delegate access to implementation """
        return getattr(self.__instance, attr)

    def __setattr__(self, attr, value):
        """ Delegate access to implementation """
        return setattr(self.__instance, attr, value)

class A:
    def __init__(self):
        self.log = logging.getLogger()
        self.log.debug("Init %s" % self.__class__.__name__)
        self.lowclass = Singleton()
        self.id = self.lowclass.id()
        self.log.debug("ID: %s" % self.id)

class B:
    def __init__(self):
        self.log = logging.getLogger()
        self.log.debug("Init %s" % self.__class__.__name__)
        self.lowclass = Singleton()
        self.id = self.lowclass.id()
        self.log.debug("ID: %s" % self.id)


class ATests(unittest.TestCase):

    def testOne(self):
        a = A()
        aid = a.id
        b = B()
        bid = b.id
        self.assertEqual(a.id, b.id)

        #
        # How do I destroy this thing??
        #

        del a
        del b

        a1 = A()
        a1id = a1.id
        self.assertNotEqual(a1id, aid)

if __name__ == '__main__':
    # Set's up a basic logger
    logging.basicConfig( format="%(asctime)s %(levelname)-8s %(module)s %(funcName)s %(message)s", 
                         datefmt="%H:%M:%S", stream=sys.stderr )
    log = logging.getLogger("")
    log.setLevel(LOGLEVEL)
    # 
    suite = unittest.TestLoader().loadTestsFromTestCase(ATests)
    sys.exit(unittest.TextTestRunner(verbosity=LOGLEVEL).run(suite))
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 8

作为Borg的作者,我显然是第二个@mjv的评论,但是,无论是Borg(又名"monostate")还是Highlander(又名"singleton"),你都需要添加一个"drop everything"方法来支持tearDown你的测试套件.用单个前导下划线命名这样的方法告诉sw的其他部分不要单独使用,但测试是非典型的野兽,并且经常需要使用其他内部属性进行捣乱.

所以,对于你的具体情况,

class Singleton:
   ...
   def _drop(self):
   "Drop the instance (for testing purposes)."
   Singleton.__instance = None
   del self._Singleton__instance
Run Code Online (Sandbox Code Playgroud)

类似地,对于Borg,一种_drop方法将释放并清除共享字典并将其替换为全新的字典.

  • 我不太确定您在考虑自己的单个实例“消失”的保证–但这可能比您想象的要弱。使用标准库的atexit模块注册一个可以在程序终止时合理地保证_is_被调用的函数,但是当一切仍处于可用状态时,例如日志记录,邮件发送,删除临时文件等等( “合理地”是因为崩溃或`kill -9`不提供任何保证;-)。现在,您需要唯一的是(通常)_state_,而Borg可以。 (2认同)